前言
算法题中有一类是专门应用某种定理而存在的题,是一种理解容易,想到很难,即问题转换的非常巧妙的一类题,通常称其为脑筋急转弯,全当长见识。
一、连续的子数组和
二、同余定理
package everyday.prefix;
import java.util.HashMap;
import java.util.Map;
// 连续的子数组和
public class CheckSubarraySum {
/*
做不来,看提示,当两个前缀和对k的余数相同时,且两者间距大于0,则存在这样的数。
这是典型的脑筋急转弯型,因为问题转换的过于巧妙!
朴素做法时间复杂度太高,从倍数角度 转到 余数角度 + 前缀和差值,复杂度降到线性级别。
资料显示,这也称同余定理,当两数对同数k取余相等时,两数之差为k的倍数,理解容易,想到很难。
*/
public boolean checkSubarraySum(int[] nums, int k) {
// 记录余数的初始位置。
Map<Integer, Integer> fx = new HashMap<>();
// 初始化余数0,在-1位置上。
fx.put(0, -1);
// 计算前缀和,并同时记录余数的初始位置。
int[] prefix = new int[nums.length];
prefix[0] = nums[0];
if (!fx.containsKey(prefix[0] % k)) fx.put(prefix[0] % k, 0);
for (int i = 1; i < nums.length; i++) {
prefix[i] = prefix[i - 1] + nums[i];
int mod = prefix[i] % k;
if (i - fx.getOrDefault(mod, i) > 1) return true;
if (!fx.containsKey(mod)) fx.put(mod, i);
}
return false;
}
}
总结
1)做不来的题马上看题解提示,然后coding,不浪费时间,也不浪费思考机会,做到真正的不浪费时间。
2)脑筋急转弯算法题,即问题转换的弯度过于大,刷它权当张见识。
3)同余定理,当两数对同数k取余相等时,两数之差为k的倍数。
参考文献
[1] LeetCode 连续的子数组和