题目描述(传送门)
给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:
子数组大小 至少为 2 ,且
子数组元素总和为 k 的倍数。
如果存在,返回 true ;否则,返回 false 。
如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 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
解题思路
暴力遍历(超时)
package com.josvin;
/**
* @ClassName Main
* @Description :TODO
* @Author Josvin
* @Date 2021/06/02/15:01
*/
public class Main {
public boolean checkSubarraySum(int[] nums, int k) {
for (int i = 0; i < nums.length; i++) {
int num = nums[i];
for (int j = i + 1; j < nums.length; j++) {
num += nums[j];
if (num % k == 0) {
return true;
}
}
}
return false;
}
}
同余定理&&hashmap&&前缀和
package com.josvin;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName Main
* @Description :TODO
* @Author Josvin
* @Date 2021/06/02/15:01
*/
public class Main {
public static boolean checkSubarraySum(int[] nums, int k) {
// 同余定理:如果两个整数m、n满足n-m能被k整除,那么n和m对k同余
//
// 即 ( pre(j) - pre (i) ) % k == 0 则 pre(j) % k == pre(i) % k
int len = nums.length;
if (len < 2) {
return false;
}
//哈希表存储每个余数第一次出现的下标
Map<Integer, Integer> map = new HashMap<>();
//规定空的前缀的结束下标为 −1,由于空的前缀的元素和为 0,因此在哈希表中存入键值对 (0,−1)。
map.put(0, -1);
int temp = 0;
for (int i = 0; i < len; i++) {
temp = (temp + nums[i]) % k;
if (map.containsKey(temp)) {
int prevIndex = map.get(temp);
if (i - prevIndex >= 2) {
return true;
}
} else {
map.put(temp, i);
}
}
return false;
}
public static void main(String[] args) {
int[] nums = {23, 2, 4, 6, 7};
int k = 6;
System.out.println(checkSubarraySum(nums, k));
}
}