leetcode五月每日一题 leetcode560

在这里插入图片描述
这一题刚开始想的就是暴力解法,但是由于题目中给的数据量过大,如果用暴力解法的话,就是O(n^3)的时间复杂度,肯定超出了时间限制

在暴力解法中充斥着很多的重复计算,所以我们可以进一步想到用cur数组,来记录从nums[0]到nums[i]的sum和

cur[i] 记录的是nums[0] + nums[1] + ... +nums[i]的和

然后按照暴力解法,遍历每一个子数组,看看是否存在cur[j] - cur[i] == k,存在则在最后返回的res上加一

但是不幸的是这个方法也是会时间超时,代码先贴上

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {

        vector<int> cur(nums.size() + 1 ,0);

        int res = 0;

        for( int i = 1; i <= nums.size(); ++ i){
            cur[i] = cur[i-1] + nums[i-1];
        }

        for(int i = 0 ; i < cur.size(); ++ i){
            for(int j = i+1; j < cur.size(); ++ j){
                if(cur[j] - cur[i] == k)
                    res ++;
            }
        }

        return res;
    }
};

那怎么解决呢?于是我就查了一下,康到这个up主讲解的挺好的:这里
在这里插入图片描述
也就是方法三:其将方法二的所有的前缀和存储到一个map中
map中键表示前缀和,值表示出现的次数
再查找 j < i时的前缀和中(即当前这个前缀和之前的元素中的前缀和,这一点很重要,不可以异步进行,不然测试用例 [1] 0过不了),是否有和等于sum-k的,其个数即为和为k的个数

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {

        if(nums.empty()) return 0;

        unordered_map<int,int> counts{{0,1}};
        int sum = 0 ;
        int ans = 0;

        for(const int num : nums){
            sum += num; //这一步和下一步不可以分开,这样就没法保证图片上的 j < i 了
            ans += counts[sum - k];
            ++counts[sum];
        }

        return ans;

    }
};


错误示范,没有将 sum += num; ans += counts[sum - k];这两步放一起(即没有考虑 j < i ),会出现测试用例[1] 0不过:

class Solution {
public:
   int subarraySum(vector<int>& nums, int k) {

       int res = 0;

       map<int,int> SumTimes;
       
      // SumTimes.insert(make_pair(0,1)); //要插入一个为0的不然就会漏算
        //但这样测试用例 [1] 0不太行

       vector<int> cur(nums.size() + 1 ,0);

       //注意数组越界
       for( int i = 1; i < nums.size() + 1; ++ i){
           cur[i] = cur[i-1] + nums[i-1];
       }

       for(int i = 1; i < cur.size() ; ++ i){
           if( SumTimes.find(cur[i]) == SumTimes.end() )
               SumTimes.insert(make_pair(cur[i],1));
           else
               SumTimes[cur[i]] ++;

       }

       //遍历map,看看有多少前缀为sum - k 的
       for(int i = 1 ; i < cur.size() ; ++ i){ //这里不应该另起炉灶
           if( cur[i] - k == 0 ){
               res ++; continue;
           }

           // 即这里要求 j 要小于i 啊
           //这里有问题啊 当测试用例为[1] 0的时候
           if( SumTimes.find(cur[i] - k) != SumTimes.end() )
               res += SumTimes[cur[i]];
       }

       return res;

   }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五月的天气

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值