前缀和总结

目录

总结:

523.连续子数组的和

 1. 学习到的知识点:

2. 算法思想:

525. 连续数组

560. 和为 K 的子数组

算法思路:

974. 和可被 K 整除的子数组

算法思路:

1248. 统计「优美子数组」

 1. 学习到的知识点:

2.算法思路:


总结:

①关于hashmap的初始化,求个数就存个数,哨兵存(0,1) 求长度就存下标,哨兵存(0,-1)

②元素只有0、1的一般要初始化把0变化为-1

③模板里面的hashmap.put的位置:

if...else里面时:一般统计长度,因为hashmap记录的是第一次出现的

if 后面时:每次循环必定执行,一般是求个数


523.连续子数组的和

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. 连续数组

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 的子数组

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 整除的子数组

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. 统计「优美子数组」

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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值