Leetcode 974 Subarray Sums Divisible by K

原题地址https://leetcode.com/problems/subarray-sums-divisible-by-k/
难度:Medium

题目:Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have a sum divisible by K.
即给一个数组A,返回Sum可以被K整除的子数组的个数。

例子:
Input: A = [4,5,0,-2,-3,1], K = 5
Output: 7
Explanation: [4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]

解析:
暴力的方法很容易得解,即时间复杂度O(n)的做法,计算A数组的所有子数组的Sum并且对K求余,统计可以整除的子数组个数即可得到解。
但是我们发现在整个求和的过程中,有很多的计算是重复进行了多次的,所以本题一定有优化的方法,于是我们想到通过前缀和(prefix sum)相减的方法一样可以求得子数组的sum,比如我们求例子数组的第3-5项(sum[3,4,5])的和时,可以:

sum[3,4,5] = sum[1,2,3,4,5] - sum[1,2]
然后我们发现当sum[1,2] 与 sum[1,2,3,4,5] 除K的余数相同时,我们可以得到 sum[3,4,5]可以被K整除,例如对于数组[1,3,2,5,1], K = 5时,

prefixSum[1] = sum[1] % 5 = 1;
prefixSum[2] = sum[1,2] % 5 = 4;
prefixSum[3] = sum[1,2,3] % 5 = 1;
prefixSum[4] = sum[1,2,3,4] % 5 = 1;
predixSum[5] = sum[1,2,3,4,5] % 5 = 2;

我们发现prefixSum[1],[3],[4]除5的余数都是1,可以说明prefixSum[3] - prefixSum[1]即sum[2,3]可以被5整除,同理,sum[4]和sum[2,3,4]也可以被5整除,则我们可以得到本题的解题思路即:

计算并记录prefixSum除K的余数, 每次计算新的prefixSum则找到之前出现过与之除K余数相同的prefixSum的个数,加入到结果中。

class Solution {
public:
    int subarraysDivByK(vector<int>& A, int K) {
        vector<int> prefix(K);
        int res = 0, curSum = 0;
        prefix[0] = 1;
        for(int num: A){
            curSum += num;
            res += prefix[(curSum % K + K) % K]++;
        }
        return res;
    }
};

注意:关于代码中的 (curSum % K + K) % K
这个涉及到负数取模运算的问题,实际上取模运算的过程如下,例如7 % 3:
7 % 3 = 7 - (7 / 3) * 3 = 7 - 2 * 3 = 1
但是如果是 -7 % 3呢?
-7 % 3 = -7 - ( -7 / 3) * 3
这个-7/3的结果是多少呢,不同的语言的计算方式不一样,对于Java和C++来说,他们采取的除法方式为truncate,即我们所说的去尾法,则 7 / 3 = 2, -7 / 3 = -2,而对于python来说采取的方式为floor,即向下取整,7 / 3 = 2, -7 / 3 = -3,由此我们再计算取模运算:

C++ & Java: 
-7 % 3 = -7 - ( -7 / 3) * 3 = -7 - (-2) * 3 = -7 + 6 = -1 
Python:
-7 % 3 = -7 - ( -7 / 3) * 3 = -7 - (-3) * 3 = -7 + 9 = 2

为了保证结果一致,即余数都为正数,使用Java和C++的时候我们写成:
(curSum % K + K) % K
使用python时可以直接写成:
curSum % K

以上

猜你喜欢

转载自blog.csdn.net/weixin_40164399/article/details/86644273