当前位置:网站首页>leetcode:560. 和为 K 的子数组
leetcode:560. 和为 K 的子数组
2022-06-29 03:21:00 【OceanStar的学习笔记】
题目来源
题目描述

class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
return process(nums, 0, k);
}
};
题目解析
双指针和滑动窗口使用的一个必要条件就是能一步一步迭代,确定窗口的收缩方向,这有负数,就完全不知道是左边缩小,还是右边缩小了
枚举
思路:把所有的子数组都穷举出来,算它们的和,看看谁的和等于k
枚举左右边界
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int len = nums.size();
int cnt = 0;
for (int left = 0; left < len; ++left) {
for (int right = left; right < len; ++right) {
int sum = 0;
for (int i = left; i <= right; ++i) {
sum += nums[i];
}
if(sum == k){
cnt++;
}
}
}
return cnt;
}
};

边枚举边计算(也超时了)
先固定起点,然后枚举右边界,时间复杂度降低了一维
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int len = nums.size();
int cnt = 0;
for (int left = 0; left < len; ++left) {
int sum = 0;
for (int right = left; right < len; ++right) {
sum += nums[right];
if(sum == k){
++cnt;
}
}
}
return cnt;
}
};

怎么优化呢?关键在于如何快速得到某个子数组的和,我们也可以用前缀和来解决
前缀和
什么是前缀和
对于一个给定的数组num,我们额外开辟一个前缀和数组进行预处理
int n = nums.length;
// 前缀和数组
std::vector<int> preSum(n + 1, 0);
preSum[0] = 0;
for (int i = 0; i < n; i++)
preSum[i + 1] = preSum[i] + nums[i];

preSum[i]就是nums[0..... i-1]的和。如果我们想要求nums[i...j]的和,只需要求preSum[j+1] - preSum[i]即可,而不需要重新去遍历数组了
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int len = nums.size();
// 构造前缀和
std::vector<int> preSum(len + 1);
preSum[0] = 0;
for (int i = 0; i < len; ++i) {
preSum[i + 1] = preSum[i] + nums[i];
}
int cnt = 0;
// 穷举所有子数组
for (int left = 0; left < len; ++left) {
for (int right = left; right < len; ++right) {
if(preSum[right + 1] - preSum[left] == k){
++cnt;
}
}
}
return cnt;
}
};
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int len = nums.size();
// 构造前缀和
std::vector<int> preSum(len + 1);
preSum[0] = 0;
for (int i = 0; i < len; ++i) {
preSum[i + 1] = preSum[i] + nums[i];
}
int cnt = 0;
// 穷举所有子数组
for (int end = 1; end <= len; ++end) {
for (int start = 0; start < end; ++start) {
if(preSum[end] - preSum[start] == k){
++cnt;
}
}
}
return cnt;
}
};
还是超时了

前缀和 + 哈希
由于我们只关心次数,不关心具体的解,所以我们可以使用哈希表来加速运算。
主要思路:计算完包括了当前树前缀和之后,我们去查一查在当前树之前,有多少个前缀和等于preSum - k呢?
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
std::vector<int> preSum(nums.size() + 1);
preSum[0] = 0;
for (int i = 0; i < nums.size(); ++i) {
preSum[i + 1] = preSum[i] + nums[i];
}
std::unordered_map<int, int> map; // key 为前缀和,value为前缀和为key的个数,问题转化为和为k的问题
map[0] = 1;
int cnt = 0;
for (int i = 1; i < preSum.size(); ++i) {
if(map.count(preSum[i] - k)){
cnt = cnt + map[preSum[i] - k]; // 如果有与当前prefixSum[i]的差为k的,则加上它的个数
}
++map[preSum[i]];
}
return cnt;
}
};
用递归实现:
class Solution {
int process(vector<int>& nums, int target, int currSum, int idx, std::unordered_map<int, int> &map){
if(idx == nums.size()){
return 0;
}
//当前的前缀和
currSum += nums[idx];
int res = 0;
res += map[currSum - target];
++map[currSum];
res += process(nums, target, currSum, idx + 1, map);
return res;
}
public:
int subarraySum(vector<int>& nums, int k) {
std::unordered_map<int, int> map; // key 为前缀和,value为前缀和为key的个数,问题转化为和为k的问题
map[0] = 1;
return process(nums, k, 0, 0, map);
}
};
边栏推荐
- Unable to locate program input point [email protected]
- 今日直播|Apache Pulsar x KubeSphere 在线 Meetup 火热来袭
- [North Asia data recovery] data recovery case of ibm-ds3512 storage server RAID5 damaged data loss
- 无法定位程序输入点 [email protected]
- MySQL advanced SQL statement (Part 2)
- 【线程通信】
- priority_ Understanding of queue
- Is it safe to open a stock account by mobile phone? Is it difficult to open an account?
- Certification training | streamnational certification training phase 2
- Getting started with testing - integration testing
猜你喜欢

深入解析 Apache BookKeeper 系列:第三篇——读取原理

2022-2028 global industrial lithium chloride industry research and trend analysis report

Problem - ADB shellerror: insufficient permissions for device: verify udev rules

Grafana Getting Started tutorial

Redu.us took the initiative to transform, and the operation leader of China's charging pile emerged

FPGA (VII) RTL code III (complex circuit design 2)

深度解析“链动2+1”模式的商业逻辑

嵌入式开发如何进行源代码保密工作

Matlab exercises - image drawing exercises
![Synchronous real-time data of Jerry's watch [chapter]](/img/6f/719aa14fb376aba45472783886dbff.jpg)
Synchronous real-time data of Jerry's watch [chapter]
随机推荐
Yyds dry inventory difference between bazel and gradle tools
Gartner's "voice of customers" has the highest score, and the user experience has become a major breakthrough for China's database
19.03 容器的说明和简单应用例续
Equal wealth
Vscode plug-in used now
Provide ideas in old texts
无法定位程序输入点 [email protected]
Bluebridge cup 2022 preliminaries - minesweeping
Probe into metacosmic storage, the next explosive point in the data storage market?
Tu ne peux pas comprendre le feu?
Grafana Getting Started tutorial
嵌入式开发如何进行源代码保密工作
如何在关闭socket连接的时候跳过TIME_WAIT的等待状态
Which is the product with the highest interest rate of increased life insurance on the market at present?
Etcd tutorial - Chapter 6 etcd core API V3
Etcd tutorial - Chapter 7 etcd transaction API
MySQL advanced SQL statement (Part 2)
VIM configuration and use
Certification training | streamnational certification training phase 2
使用gdb添加断点的几种方式