package substring; import java.util.HashMap; /** * 题目:523. 连续的子数组和 (checkSubarraySum) * 描述:给你一个整数数组 nums 和一个整数 k ,如果 nums 有一个 好的子数组 返回 true ,否则返回 false: 一个 好的子数组 是: 长度 至少为 2 ,且 * 子数组元素总和为 k 的倍数。 * 注意: * 子数组 是数组中 连续 的部分。 * 如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 k 的一个倍数。0 始终 视为 k 的一个倍数。 * * 链接:https://leetcode.cn/problems/continuous-subarray-sum/ 示例 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 */ //需重做 //本题不一样的地方是无需统计个数,故哈希表中键值可以存索引。 public class CheckSubarraySum { //枚举法超时 public boolean checkSubarraySum1(int[] nums, int k) { for (int left = 0; left < nums.length; left++) { int tpsum=nums[left]; for (int right = left+1; right < nums.length; right++) { tpsum+=nums[right]; if(tpsum%k==0) return true; } } return false; } //前缀和 这题需要判断子数组和是否为 k 的倍数,因此我们关心的是前缀和对 k 取余后的值是否相等 public boolean checkSubarraySum(int[] nums, int k) { // 特殊情况:k == 0 的处理,寻找连续和为 0 的子数组 if (k == 0) { for (int i = 0; i < nums.length - 1; i++) { if (nums[i] == 0 && nums[i+1] == 0) { return true; } } return false; } // 哈希表存储前缀和 mod k 的余数及其第一次出现的下标 HashMap modMap = new HashMap<>(); modMap.put(0, -1); // 余数为0时,将下标设为-1,方便处理从数组开头开始的情况 int prefixSum = 0; for (int i = 0; i < nums.length; i++) { prefixSum += nums[i]; int mod = prefixSum % k; // 如果这个余数之前出现过,则当前下标和之前下标之差至少大于1 if (modMap.containsKey(mod)) { if (i - modMap.get(mod) > 1) { return true; } } else { // 记录第一次出现该余数的下标 modMap.put(mod, i); } } return false; } }