[LeetCode] 930. Binary Subarrays With Sum My SubmissionsBack to Contest

题: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:

  1. A.length <= 30000
  2. 0 <= S <= A.length0 <= S <= A.length
  3. 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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值