概述
题:https://leetcode.com/contest/weekly-contest-108
题目
In an array A of 0s and 1s, how many non-empty subarrays have sum S?
Example 1:
Input: A = [1,0,1,0,1], S = 2
Output: 4
Explanation:
The 4 subarrays are bolded below:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
Note:
- A.length <= 30000
- 0 <= S <= A.length0 <= S <= A.length
- A[i] is either 0 or 1.A[i] is either 0 or 1.
题目大意
一个 由 0、1组成 的子串,统计所有 子串和为S 的数量。
思路
子串求和,一般可以先转化为A[] -> sum[]。这样 sum[i] - sum[j] 便是 子串 和,减少计算量。
sum[0] = 0; (便于计算统一)
sum[i] = A[0]+A[1]+…+A[i-1] 。
sum[i] - sum[j] 便是 子串和。
由于 串为 0、1组成,sum[] 为递增。
问题转化为 求递增 数组 sum[] 中两元素 差为S 的数量。
方法一
确定一个数sum[i] 然后 找 元素 为 remainder = sum[i] - S 的个数。同时考虑到 sum[i] 递增,所以从 j = i - 1 往前查找。若 出现sum[j]<remainder ,退出循环,因为 sum[0:j]更小。
最坏 时间复杂度 O(n2) ,Runtime: 891 ms ,性能表现的确很差。
class Solution {
public int numSubarraysWithSum(int[] A, int S) {
int[] tsum = new int[A.length+1];
for(int i = 1;i < tsum.length;i++){
tsum[i] = tsum[i-1] + A[i-1];
}
int res = 0;
for(int i = 1;i < tsum.length;i++){
int remainder = tsum[i] - S;
for(int j = i - 1;j>=0;j--){
if(remainder == tsum[j])
res++;
else if(remainder>tsum[j])
break;
}
}
return res;
}
}
方法二 优化 查找
查找 有序串 指定值 的个数。
使用 lowerBound 函数 与 upperBound 函数。
时间复杂度 O(n logn)
class Solution {
public static int lowerBound(int []nums,int l,int r,int target){
while(l<r){
int m = (l+r)/2;
if(nums[m]>=target) r= m;
else l = m +1;
}
return l;
}
public static int upperBound(int []nums ,int l,int r, int target){
while(l<r){
int m = (l+r)/2;
if(nums[m]<=target) l = m+1;
else r = m;
}
return l;
}
public int numSubarraysWithSum(int[] A, int S) {
int[] tsum = new int[A.length+1];
int lastnum = 0 ;
for(int i = 1;i < tsum.length;i++){
tsum[i] = tsum[i-1] + A[i-1];
}
int res = 0;
for(int i = 1;i < tsum.length;i++){
int remainder = tsum[i] - S;
int il = lowerBound(tsum,0,i,remainder);
int ir = upperBound(tsum,0,i,remainder);
res += ir - il;
}
return res;
}
}
方法三 Hashmap
问题可以视为 在 数组 sum[] 中 找出 组合的数量,组合<sum[j],sum[i]> 满足 sum[j] + S == sum[i]且j<i。
定义 map 、key = 数组sum中的元素:value = 元素出现的个数。
遍历 map :num;
若 map.containsKey(num+S) ,res += map.get(num) * map.get(num+S)。即 若 num、num +S 在数组中,那么 这样 的组合数 map.get(num) * map.get(num+S)。
当 若S 为 0 时候,就是在 num 中 找 组合数(<sum[j],sum[i]>,sum[j] = sum[i]=num) 组合数为 C2n 。
class Solution {
public int numSubarraysWithSum(int[] A, int S) {
int[] tsum = new int[A.length+1];
Map<Integer,Integer> map = new HashMap<>();
map.put(0,1);
for(int i = 1;i < tsum.length;i++){
tsum[i] = tsum[i-1] + A[i-1];
map.put(tsum[i],map.getOrDefault(tsum[i],0)+1);
}
int res = 0;
for(int num:map.keySet()){
if(S == 0)
res += map.get(num)*(map.get(num)-1)/2;
else
if(map.containsKey(num+S))
res += map.get(num)*map.get(num+S);
}
return res;
}
}
最后
以上就是喜悦镜子为你收集整理的[LeetCode] 930. Binary Subarrays With Sum My SubmissionsBack to Contest题目思路的全部内容,希望文章能够帮你解决[LeetCode] 930. Binary Subarrays With Sum My SubmissionsBack to Contest题目思路所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复