[LeetCode]974. 和可被 K 整除的子數組

題目

給定一個整數數組 A,返回其中元素之和可被 K 整除的(連續、非空)子數組的數目。

示例:

輸入:A = [4,5,0,-2,-3,1], K = 5
輸出:7
解釋:
有 7 個子數組滿足其元素之和可被 K = 5 整除:
[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]

提示:

  1. 1 <= A.length <= 30000
  2. -10000 <= A[i] <= 10000
  3. 2 <= K <= 10000

解題思路

本題與(560. 和爲K的子數組)非常類似,詳情可參考560. 和爲K的子數組
解法一:前綴和 + 哈希表優化
定義數組 sum[j] 爲[0…j]所有元素的和,那麼[i…j]這個子數組的和可以表示爲 s[i…j]=sum[j]-sum[i-1],要使這個子數組的和可被k整除,即 (sum[j]-sum[i-1]) mod k == 0,也即 sum[j] mod k == sum[i-1] mod k。因此只需要找有多少對累加和sum mod k 相同的數就可以組合一下得到結果。
這可以藉助哈希表保存累加和sum mod k的值以及出現的次數,若相同的(sum mod k)已經出現過,則說明存在連續子數組之和可被k整除。由於 sum[i] 的計算只與前一項的答案有關,因此我們可以不用建立 sum 數組,直接用一個 sum 變量來記錄 sum[i−1] 的答案即可。

具體做法是:
1)初始化哈希表hash={0:1},表示累加和sum mod k=0,出現了1次。初始化累加和sum=0。初始化結果res=0。
2)遍歷數組:
2.1)更新累加和sum += nums[i];
2.2)若sum mod k存在於hash中,說明存在連續子數組之和可被k整除。則令res += hash[sum mod k],表示sum mod k出現幾次,就存在幾種子數組之和可被k整除。
2.3)若sum mod k 存在於hash中,將其出現次數加一。若不存在,將其加入hash。
3)返回res。

複雜度分析:
時間複雜度:O(N),其中 N 是數組 A 的長度。我們只需要從前往後遍歷一次數組,在遍歷數組的過程中,維護哈希表的各個操作均爲 O(1),因此總時間複雜度爲 O(N)。
空間複雜度:O(min(N,K)),即哈希表需要的空間。當 N≤K 時,最多有 N 個前綴和,因此哈希表中最多有 N+1 個鍵值對;當 N>K 時,最多有 K 個不同的餘數,因此哈希表中最多有 K 個鍵值對。也就是說,哈希表需要的空間取決於 N 和 K 中的較小值。

注:
本題有個注意點,取模與取餘的區別,其實取模和取餘在目標上是一致的,但是因爲語言對取餘和取模上定義的不同,導致得到的結果不同。對取餘和取模定義不同的語言中,兩者的不同點只有一個:
1)取餘運算在計算商值向0方向捨棄小數位;
2)取模運算在計算商值向負無窮方向捨棄小數位。
或者也可以這樣理解:
1)取餘,遵循儘可能讓商大的原則
2)取模,遵循儘可能讓商小的原則
從上面的區別可以總結出,取餘(rem)和取模(mod)在被除數、除數同號時,結果是等同的,異號時會有區別,所以要特別注意異號的情況。

一些例子:
取餘:

5 rem 3 = 2 (5=1*3+2,商爲1)
-5 rem 3 = -2 (-5=(-1)*3-2,商爲-1)
5 rem -3 = 2 (5=(-1)*(-3)+2,商爲-1)
-5 rem -3 = -2 (-5=1*(-3)-2,商爲1)

取模:

5 mod 3 = 2 (5=1*3+2,商爲1)
-5 mod 3 = 1 (-5=(-2)*3+1,商爲-2)
5 mod -3 = -1 (5=(-2)*(-3)-1,商爲-2)
-5 mod -3 = -2 (-5=1*(-3)-2,商爲1)

在C/C++, C#, JAVA, PHP這幾門主流語言中,’%’運算符都是做取餘運算,而在python中的’%’是做取模運算。

代碼

Python代碼如下:

class Solution:
    def subarraysDivByK(self, A: List[int], K: int) -> int:
        hash_dic = {0:1}
        res = 0
        s = 0
        for i in range(len(A)):
            s += A[i]
            if s % K in hash_dic:
                res += hash_dic[s%K]
                hash_dic[s%K] += 1
            else:
                hash_dic[s%K] = 1
        return res

Java代碼如下:

class Solution {
    public int subarraysDivByK(int[] A, int K) {
        HashMap<Integer, Integer> hash = new HashMap<Integer, Integer>();
        hash.put(0, 1);
        int res = 0;
        int s = 0;
        for(int i=0; i<A.length; i++){
            s += A[i];
            int mod = Math.floorMod(s, K);
            if(hash.containsKey(mod)){
                res += hash.get(mod);
                hash.put(mod, hash.get(mod)+1);
            }else{
                hash.put(mod, 1);
            }
        }
        return res;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章