目录
总结:
①关于hashmap的初始化,求个数就存个数,哨兵存(0,1) 求长度就存下标,哨兵存(0,-1)
②元素只有0、1的一般要初始化把0变化为-1
③模板里面的hashmap.put的位置:
if...else里面时:一般统计长度,因为hashmap记录的是第一次出现的
if 后面时:每次循环必定执行,一般是求个数
523.连续子数组的和
1. 学习到的知识点:
前缀和 + 同余定理 + 哈希表
首先,先看一个例子:假如一个数字是3, k = 7, 此时3 % 7 = 3; 如果3后面有一个7会怎么样?此时3+7 % 7= 3。说明了如果一个前缀和余k 和 在他之后的前缀和余k 相等,那么他们中间的数字的和是k的倍数。
2. 算法思想:
创建一个哈希表,key来储存当前前缀和的余数,value则储存对应的index
如果哈希表中存在其对应的余数,取出其pos,看当前的下标 index到 pos的距离是否大于等于2. 如果是则返回true。不是我们则继续遍历。不要更新哈希表中的下标!(贪心的思维)
如果不存在则将当前余数与其对应的下标储存在哈希表中。
class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
int ans = 0, sum = 0;
for(int i = 0; i < nums.length; ++i){
sum += nums[i];
if(map.containsKey(sum % k)){
if( i - map.get(sum % k) >= 2){
return true;
}
}else map.put(sum % k, i);
}
return false;
}
}
525. 连续数组
class Solution {
public int findMaxLength(int[] nums) {
int n = nums.length;
for(int i = 0; i < n; i++){
if(nums[i] == 0) nums[i] = -1;
}
int sum = 0, ans = 0;
Map<Integer, Integer> hashmap = new HashMap<>();
hashmap.put(0, -1);
for(int i = 0; i < n; i++) {
sum += nums[i];
if(hashmap.containsKey(sum)){
ans = Math.max(ans, i - hashmap.get(sum));
}else{
hashmap.put(sum, i);
}
}
return ans;
}
}
560. 和为 K 的子数组
算法思路:
前缀和 + 哈希表,key存储的是preSum,value存储的是某个preSum出现的次数
import java.util.HashMap;
import java.util.Map;
public class Solution {
public int subarraySum(int[] nums, int k) {
// key:前缀和,value:key 对应的前缀和的个数
Map<Integer, Integer> hashmap = new HashMap<>();
// 对于下标为 0 的元素,前缀和为 0,个数为 1
hashmap.put(0, 1);
int preSum = 0;
int count = 0;
for (int num : nums) {
preSum += num;
// 先获得前缀和为 preSum - k 的个数,加到计数变量里
if (hashmap.containsKey(preSum - k)) {
count += hashmap.get(preSum - k);
}
// 然后维护 preSumFreq 的定义
hashmap.put(preSum, hashmap.getOrDefault(preSum, 0) + 1);
}
return count;
}
}
974. 和可被 K 整除的子数组
学习的知识点:将负数( item % k + k )即等价于正数取余。
拿K = 4为例,求出某个前缀和为 -1,-1 % K 应该为 3,但有的编程语言 -1 % K = -1。这个 -1,要加上 K,转成正 3。
为什么 preSum 值为 -1 和 3 需要归为同一类?因为:-1 和 3 分别模 4 的结果看似不相等,但前缀和之差:3 - ( - 1) 等于 4。4 % K = 0,即所形成的子数组满足元素和被 4 整除。所以前缀和 -1 和 3 其实是等价的。
算法思路:
前缀和的哈希表key记录的是余数,value记录的是余数出现的次数。
class Solution {
public int subarraysDivByK(int[] A, int K) {
Map<Integer, Integer> hashmap = new HashMap<>();
int sum = 0, ans = 0;
hashmap.put(0, 1);
for (int item : A) {
sum += item;
if(sum < 0){ // 纠正 Java 除余操作会导致负数的情况
sum = sum % K + K;
}
ans += hashmap.getOrDefault(sum % K, 0);
hashmap.put(sum % K, hashmap.getOrDefault(sum % K, 0) + 1);
}
return ans;
}
}
1248. 统计「优美子数组」
1. 学习到的知识点:
前缀和 + 哈希表
2.算法思路:
哈希表key存储以该位置结尾的奇数元素的个数,value该sum个奇数元素出现的次数,初始化hashmap.put(0, 1),
例如:nums = [1,1,2,1,1], k = 3
某个位置的奇数元素的个数(1, 2, 2, 3, 4)存储到哈希表中就是(1,1), (2, 2), (3,1), (4,1)。一个奇数出现了一次,2个奇数出现了2次
class Solution {
public int numberOfSubarrays(int[] nums, int k) {
int n = nums.length;
int sum = 0;
Map<Integer, Integer> hashmap = new HashMap<>();
hashmap.put(0, 1);
int count = 0;
for(int i = 0; i < n; i++) {
if(nums[i] % 2 == 1) sum++;
if(hashmap.containsKey(sum - k)) { //先找前缀表
count += hashmap.get(sum-k);
}
hashmap.put(sum, hashmap.getOrDefault(sum, 0) + 1); //再把当前位置的前缀和存进哈希表
}
return count;
}
}