LeetCode算法心得——连续的子数组和(前缀和+HashMap)

大家好,我是晴天学长,同余定理的应用加上hashmap的灵活应用,需要的小伙伴可以关注支持一下哦!后续会继续更新的。


1) .连续的子数组的和

LeetCode算法心得——连续的子数组和(前缀和+HashMap)_第1张图片

题目描述:
给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:

子数组大小 至少为 2 ,且
子数组元素总和为 k 的倍数。
如果存在,返回 true ;否则,返回 false 。

如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 k 的一个倍数。0 始终视为 k 的一个倍数。

示例 1:

输入:nums = [23,2,4,6,7], k = 6
输出:true
解释:[2,4] 是一个大小为 2 的子数组,并且和为 6 。
示例 2:

输入:nums = [23,2,6,4,7], k = 6
输出:true
解释:[23, 2, 6, 4, 7] 是大小为 5 的子数组,并且和为 42 。
42 是 6 的倍数,因为 42 = 7 * 6 且 7 是一个整数。
示例 3:

输入:nums = [23,2,6,4,7], k = 13 输出:false

提示:

1 <= nums.length <= 105
0 <= nums[i] <= 109
0 <= sum(nums[i]) <= 231 - 1
1 <= k <= 231 - 1


2) .算法思路

前缀和+HashMap

解析:

我们需要求出满足条件的区间,见下图
在这里插入图片描述
我们需要找到满足,和为 K 的区间。我们此时 presum 是已知的,k 也是已知的,我们只需要找到 presum - k区间的个数,就能得到 k 的区间个数。但是我们在当前题目中应该怎么做呢?见下图。

在这里插入图片描述
我们在之前的例子中说到,presum[j+1] - presum[i] 可以得到 nums[i] + nums[i+1]+… nums[j],也就是[i,j]区间的和。

那么我们想要判断区间 [i,j] 的和是否能整除 K,也就是上图中紫色那一段是否能整除 K,那么我们只需判断

(presum[j+1] - presum[i] ) % k 是否等于 0 即可,

我们假设 (presum[j+1] - presum[i] ) % k == 0;则

presum[j+1] % k - presum[i] % k == 0;

presum[j +1] % k = presum[i] % k ;

我们 presum[j +1] % k 的值 key 是已知的,则是当前的 presum 和 k 的关系,我们只需要知道之前的前缀区间里含有相同余数 (key)的个数。则能够知道当前能够整除 K 的区间个数。见下图
在这里插入图片描述
我们看到上面代码中有一段代码是这样的
int key = (presum % K + K) % K;
这是为什么呢?不能直接用 presum % k 吗?

这是因为当我们 presum 为负数时,需要对其纠正。纠正前(-1) %2 = (-1),纠正之后 ( (-1) % 2 + 2) % 2=1 保存在哈希表中的则为 1.则不会漏掉部分情况,例如输入为 [-1,2,9],K = 2如果不对其纠正则会漏掉区间 [2] 此时 2 % 2 = 0,符合条件,但是不会被计数。

那么这个题目我们可不可以用数组,代替 map 呢?当然也是可以的,因为此时我们的哈希表存的是余数,余数最大也只不过是 K-1所以我们可以用固定长度 K 的数组来模拟哈希表。


3) .算法步骤

1.创建一个HashMap对象 map 用于存储余数与对应出现次数的映射关系。
2.初始化变量 PerSum 为0,表示当前位置的前缀和。
3.初始化变量 answer 为0,表示满足条件的子数组个数。
4.将余数为0的初始情况放入 map 中,即以0为坐标的前缀和,要计算为距离,表示为1。
5.使用一个循环遍历数组中的元素。
6.将当前元素的值累加到 PerSum 中,即计算当前位置相减是否大于等于2。
7.使用同余定理,计算当前前缀和除以k的余数,由于负数取模的结果可能为负数,为
8.确保结果为非负整数,需要进行加k再取模的操作。


4).代码示例

class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        HashMap<Integer,Integer> map = new HashMap<>();
            long Persum = 0;
              map.put(0,-1);
            for (int i = 0; i < nums.length ; i++) {
                Persum += nums[i];
                int mod = (int)(Persum%k+k)%k;
                if (map.containsKey(mod)){
                    int index = map.get(mod);
                if (i-index >=2){
                        return true;
                }
                }else
                map.put(mod,i);
            }
            return false;

    }
}

5).总结

  • HashMap的应用。
  • 存下标。

试题链接:

你可能感兴趣的:(算法,算法,leetcode,java)