930和相同的二元子数组 同560题
- 思路
求连续子数组,一般考虑前缀和。需要查找再想到哈希表。
sum[i]表示数组nums中0~i的前缀和,假设子数组[j,i+1]和为gal,也就是sum[j]-sum[i] = gal;子数组长度为j-i;所以遍历nums,查看当前值前缀和在哈希表中存在的个数x,就说明当前值为结尾的子数组和为gal的子数组个数为x个 - 代码解析
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
int len = nums.size();
unordered_map<int,int> hash_table;
int left = 0;
int res = 0;
for(int i = 0; i<len; ++i){
++hash_table[left];
left += nums[i];
res += hash_table[left - goal];
}
return res;
}
};
- 总结学习
1:通常情况下,涉及连续子数组问题的时候,使用前缀和来解决。
2:查找问题,考虑哈希表,且遍历时,先对当前值在哈希表中查找,然后再根据题目要求是否添加进 入哈希表
3:哈希表value值存key出现次数 当前位置下标。
974和可被 K 整除的子数组
-
思路
根据同余定理,遍历数组nums,把前缀和对K的余数存入哈希表中,判断当前位置前缀和对k求余的余数为key值的个数。
细节:1. hash[0] = 1是为了处理 k = 2 [2,3,2,…] 这种情况
2.当nums中有负数,进行求余要rem = (left%k+k)%k
原因:
拿K = 4为例,求出某个前缀和为 -1,-1 % K 应该为 3,但有的编程语言 -1 % K = -1
这个 -1,要加上 K,转成正 3。
为什么 preSum 值为 -1 和 3 需要归为同一类?
因为:-1 和 3 分别模 4 的结果看似不相等,但前缀和之差:(-1)-(3)等于4。4 % K = 0,即所形成的子数组满足元素和被 4 整除。所以前缀和 -1 和 3 其实是等价的。
最后处理负数的时候,讲解的前缀和之差是不是应该为(-1)-(3)?靠后的前缀和b余为-1,既b=n2k+(-1),靠前的前缀和a余为3,既a=n1k+3,所以b-a=(n2-n1)*k + (-1)-(3) 感觉这样更好理解一点 -
代码
class Solution {
public:
int subarraysDivByK(vector<int>& nums, int k) {
int len = nums.size();
int left = 0,rem = 0,res = 0;
unordered_map<int,int> hash;
hash[0] = 1;
for(int i = 0;i<len;++i){
left += nums[i];
rem = (left%k+k)%k;//rem = left%k有什么区别 就是负数的情况为甚要这么处理
if(hash.count(rem)) res += hash[rem];
++hash[rem];
}
return res;
}
};
- 总结学习
1:C++ 负数求余
2:数学知识吧 对于思路中的 负余数a加k==正余数b 则也符合同余定理
525. 连续数组
给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
第二遍没做出来
- 用什么方法?为什么用这个方法?
求符合某条件的子数组最长长度,考虑转化为前缀和来统计满足某条件的子数组,前缀和下标求子数组长度。然后根据题目只有两种元素(0 1)把0转换成-1,当两个元素前缀和相同时,说明这两个元素(前开后闭)为边界的区间的子数组 01个数相同。 - 代码
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int len = nums.size();
unordered_map<int,int> hash;
int sum = 0;
int maxlen = 0;
hash[0] = -1;
for(int i = 0;i<len;i++){
sum += nums[i]>0?1:-1;
if(hash.count(sum)){
int temp = hash[sum];
maxlen = max(maxlen,i-temp);
}else{
hash[sum] = i;
}
}
return maxlen;
}
};
- 学到了什么?
使用前缀和统计子数组时,一定要先搞清楚子数组长度与前缀和下标的关系!!!