赞
踩
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
示例 1:
输入:nums = [1,1,1], k = 2
输出:2
示例 2:输入:nums = [1,2,3], k = 3
输出:2来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/subarray-sum-equals-k
Leetcode中的题解为,以 i 结尾,和为 k 的连续子数组个数(太反人类了,看来半天没看懂官方的哈希表法)。这里重新记录一下,以 i 起始,和为 k 的连续子数组个数。更符合自己的解题思路。
一、暴力枚举
示例:[3, 4, 7, 2, -3, 1, 4, 2] k=7
[3, 4, 7, 2, -3, 1, 4, 2]
i j →→
[4, 7, 2, -3, 1, 4, 2]
i , j →→
定义由 i 开始的子区间 [ i, j ], 逐步向右搜索,统计该区间内 所有数的和 是否等于 k:
- class Solution {
- public:
- int subarraySum(vector<int>& nums, int k) {
- int count = 0;
- for (int i = 0; i < nums.size(); ++i) {
- int sum = 0;
- for (int j = i; j < nums.size(); ++j) {
- sum += nums[j];
- if (sum == k) {
- count++;
- }
- }
- }
- return count;
- }
- };
定义前缀和数组 preSum[],其中preSum[i]表示:nums[0, ..., i] 区间所有数的和。
显然有:preSum[i] = preSum[i - 1] + nums[i]
因此,若区间 [ i, j ],满足式 k == preSum[j] - preSum[i - 1],则满足题意。
即:
题意:有几种 i、j 的组合,使得从第 i 到 j 项的子数组和等于 k。
↓ ↓ ↓ 转化为 ↓ ↓ ↓
有几种 i、j 的组合,满足 preSum[j] - preSum[i - 1] == k
- class Solution {
- public:
- int subarraySum(vector<int>& nums, int k) {
- int count = 0;
-
- // 前缀和数组
- vector<int> preSum(nums.size(), 0);
- preSum[0] = nums[0];
- for(int i=1;i<nums.size();++i)
- {
- preSum[i] = preSum[i-1] + nums[i];
- }
-
- // [1, 1, 1, 1, 1, 1]
- // (i j)
- for(int i=0; i<nums.size(); ++i){
- for(int j=i; j<nums.size(); ++j){
- int sum;
- if(i==0)
- sum = preSum[j] - 0; //即 preSum[i - 1] 定义为0
- else
- sum = preSum[j] - preSum[i - 1];
- if(sum == k)
- ++count;
- }
- }
- return count;
- }
- };
我们可以基于方法一利用数据结构进行进一步的优化,我们知道方法一的瓶颈在于对每个 i,我们需要枚举所有的 j 来判断是否符合条件,这一步是否可以优化呢?答案是可以的。
- 由于只关心次数,不关心具体的解,我们可以使用哈希表加速运算;
- 由于保存了之前相同前缀和的个数,计算区间总数的时候不是一个一个地加,时间复杂度降到了 O(N)。
这个思路不是很容易想到,需要多做一些类似的问题慢慢培养感觉。
同类问题有:
「力扣」第 1 题:两数之和;
「力扣」第 1248 题: 统计「优美子数组」;
「力扣」第 454 题:四数相加 II。
由二
题意:有几种 i、j 的组合,使得从第 i 到 j 项的子数组和等于 k。
↓ ↓ ↓ 转化为 ↓ ↓ ↓
有几种 i、j 的组合,满足 preSum[j] - preSum[i - 1] == k即 preSum[j] - k == preSum[i - 1]
其实我们不关心具体(即可以考虑用HashMap)是哪两项的前缀和之差等于k,只关心等于 k 的前缀和之差出现的次数c,就知道了有c个子数组求和等于k。
key -- 前缀和为key value -- 前缀和为k出现的次数
- class Solution {
- public:
- int subarraySum(vector<int>& nums, int k) {
- int count = 0;
- unordered_map<int, int> preSumCountMap;
- // 前缀和数组
- // key :前缀和为key value :前缀和为k出现的次数
- preSumCountMap[0] = 1;
- int preSum=0;
- for(int j = 0; j < nums.size(); ++j)
- {
- preSum += nums[j];
- if(preSumCountMap.count(preSum - k))
- count += preSumCountMap[preSum - k];
- preSumCountMap[preSum]++;
- }
-
- return count;
- }
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。