前缀和 02

101 阅读1分钟

LeetCode 974

原题链接

代码如下:

import java.util.HashMap;
import java.util.Map;

/**
 * 前缀和
 * 
 * 设P[i] = A[0]+A[1]+...+A[i],由题意可得,sum(i,j)可被K整除
 * 所以可以转换成(P[j]-P[i-1]) % K == 0,其中(0<i<j),由同余定理可得:
 * M = P[j] % K == P[i-1] % K 即可满足条件 
 * 
 * 我们可以遍历这个数组,然后用HashMap来记录上面键M的值,随着遍历的过程
 * 如果发现后面的键M与前面的键M相同,则这个子区间符合条件
 * 
 * 边界条件是哈希表record.put(0,1),表示取到键M为0,有1个子区间,这样考虑到
 * 前缀和本身被K整除的情况
 * 
 * Code by java
 */

class Solution {
	public int subarraysDivByK(int[] A, int K) {
		Map<Integer, Integer> record = new HashMap<>();
		record.put(0, 1);				//边界条件
		int sum = 0, ans = 0;
		for (int elem : A) {
			sum += elem;				//遍历过程中,依次叠加求和,用于维护前缀和
			//防止被除数为负数时,求的键值为,可以采用以下两种方式解决
//			int modulus = (sum % K + K) % K;	//方法一
			int modulus = Math.floorMod(sum, K);	//使用向下取整
			int same = record.getOrDefault(modulus, 0);	//记录当前位置前缀和取模键的值,如果没有则表示为0
			ans += same;				//更新最终结果
			record.put(modulus, same + 1);	//维护前缀和,并且算上当前遍历的这个数,所以same+1
		}
		return ans;
	}

	public static void main(String[] args) {
		Solution a = new Solution();
		int[] p = new int[] { 4, 5, 0, -2, -3, 1 };
		System.out.println(a.subarraysDivByK(p, 5));
	}
}