【前缀和】560.和为 K 的子数组

简介: 暴力解法:我们很容易想到通过两个for循环去遍历数组中所有和的可能,之后来判断有几个满足K.他的代码十分的简单,所以这里直接给出.

Halo,这里是Ppeua。平时主要更新C++,数据结构算法,Linux与ROS…感兴趣就关注我bua!


和为K的子数组


1dea12e01be14618b17a95e208479d38.png


题目:


dddf521eddc04c80a901a17eed6ff51e.png


示例:


5d5658a5208e4495b1f73ffb9b1eda33.png


题解:


解法一:


暴力解法:我们很容易想到通过两个for循环去遍历数组中所有和的可能,之后来判断有几个满足K.他的代码十分的简单,所以这里直接给出.


class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int count = 0;
        for (int start = 0; start < nums.size(); ++start) {
            int sum = 0;
            for (int end = start; end >= 0; --end) {
                sum += nums[end];
                if (sum == k) {
                    count++;
                }
            }
        }
        return count;
    }
};


这里通过一个start与end来控制子数组区间.若为K则计数++.


我们仔细观察这样的做法.可以很容易的发现,**我们可以通过前缀和来解决两层循环的问题.**于是就有了解法二:利用前缀和来解决此类问题.


解法二:


不熟悉前缀和的uu们可以看看这篇文章:[前缀和]((138条消息) 【高精度加减乘除法、一维二维前缀和&&差分】思路讲解及代码实现_ppeua的博客-CSDN博客)


这里就直接开始推导了,这里利用的是一维的前缀和方法.


定义:**pre[i]**表示从0~i的所有数组元素之和.


那么根据前缀和的定义:j~i区间内的元素之和可以表示为:pre[i]-pre[j-1],我们要判断的就是这个结果能不能等于K.


所以现在的求解就简化为下面这个式子:


372ea79c7251413eb9692ffc7b98f597.png


我们对两边式子进行简单的数学推导可以得到.


288d7707d3ac494884a0cc49041fd72f.png


这样我们可以通过一个hash来存储值,之后只要验证当前遍历的这个前缀和-k的结果是否出现在hash当中.若出现则+上其出现的次数.


代码较为简单:


class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
       for(int i=1;i<nums.size();i++)
       {
        nums[i]+=nums[i-1];
       }
       unordered_map<int,int>mp;
       mp[0]=1;
       int res=0;
       for(int i=0;i<nums.size();i++)
       {
        if(mp.find(nums[i]-k)!=mp.end())
        {
            res+=mp[nums[i]-k];
        }
        mp[nums[i]]++;
       }
       return res;
    }
};


有两个很重点的问题:


1.为什么mp[0]=1?


为了应对 nums[0] +nums[1] + … + nums[i] == k,也就是从下标 0 累加到下标 i刚好满足的情况.


举个例子:k为6


981f5e0f58844b1a94565b62cd660aaa.png



当这种情况下,第一次遍历到原数组为3,前缀和数组为6的位置的时候.此时pre-k=0,是刚好满足情况的.所以需要先预设一个mp[0]=1的情况.


2.为什么是res+=mp[nums[i]-k]:


举个例子:K仍为6


b40763b26d72443db2fc4d1516c190a0.png


这道题的答案是4,当遍历到第一个6的位置上时,得到第一个答案.遍历到第二个位置时,得到第二个答案.这两种情况都是:pre-k=0


遍历到12时得到第三个答案,此时pre-k=6.那么此时只有三个答案嘛?不是的,12-第一个6是一个答案.12-第二个6也是一个答案.


遍历到第二个位置时,得到第二个答案.这两种情况都是:pre-k=0


遍历到12时得到第三个答案,此时pre-k=6.那么此时只有三个答案嘛?不是的,12-第一个6是一个答案.12-第二个6也是一个答案.


所以:res+=mp[nums[i]-k],是为了直接加上相同情况的可能.

目录
相关文章
|
人工智能 移动开发
【前缀和】
【前缀和】
|
3月前
|
算法
【算法】前缀和——前缀和
【算法】前缀和——前缀和
|
3月前
|
算法 C++
【算法】前缀和算法——和可被K整除的子数组
【算法】前缀和算法——和可被K整除的子数组
|
3月前
|
算法
【算法】前缀和算法——和为k的子数组之和
【算法】前缀和算法——和为k的子数组之和
|
6月前
|
人工智能
前缀和-给恐暴龙喂食
前缀和-给恐暴龙喂食
|
6月前
|
算法 测试技术 C#
二分查找|滑动窗口|前缀和|LeetCode209: 长度最小的子数组
二分查找|滑动窗口|前缀和|LeetCode209: 长度最小的子数组
|
6月前
|
人工智能 移动开发
前缀和讲解
前缀和讲解
36 0
|
6月前
|
测试技术
leetcode-152:乘积最大子数组
leetcode-152:乘积最大子数组
59 0
|
存储 算法 Linux
【前缀和】974. 和可被 K 整除的子数组
同样的,本题利用了前缀和的定理.当(pre[i]-pre[j-1])mod k==0时.即为所寻找的答案.
54 0
|
算法 C语言 C++
【前缀和】1588. 所有奇数长度子数组的和
【前缀和】1588. 所有奇数长度子数组的和
97 0