每日一道算法面試題(16):leecode 560 和爲K的子數組

1.算法題目

給定一個整數數組和一個整數 k,你需要找到該數組中和爲 k 的連續的子數組的個數。

示例 1 :

輸入:nums = [1,1,1], k = 2
輸出: 2 , [1,1] 與 [1,1] 爲兩種不同的情況。

說明 :

數組的長度爲 [1, 20,000]。
數組中元素的範圍是 [-1000, 1000] ,且整數 k 的範圍是 [-1e7, 1e7]。

2.算法思路

  1. 暴力法:考慮給定數組 sums 的每個可能的子數組,找到每個子數組的總和,並檢查總和是否等於 k,等於時遞增用於記錄所需結果的 count;時間複雜度爲 O(n^3),空間複雜度爲 O(1),超出時間限制;
  2. 使用累計和:計算數組的每個數字開始到累加後面每個數字的和,遇到和爲 k時, count 加1;需要兩層循環遍歷,時間複雜度爲 O(n^2),空間複雜度爲 O(1);
  3. 使用哈希表:使用一個哈希表 map ,它用於存儲所有可能的索引的累積總和以及相同累加和發生的次數,遍歷數組 nums 並繼續尋找累積總和。每當我們遇到一個新的和時,我們在hashmap中創建一個與該總和相對應的新條目。如果再次出現相同的和,我們增加與 map 中的和相對應的計數;對於遇到的每個總和,確定已經發生 sum-k 總和的次數,因爲它將確定具有總和 k 的子陣列到當前索引的次數,同時將 count 增加相同的數量。最後得到的 count 即爲滿足題意的值。只需要一次循環遍歷數組,但需要 map的輔助空間,時間複雜度爲 O(n),空間複雜度爲 O(n);

3.算法代碼

根據累計和算法思路,編寫的算法代碼如下:

public static int subarraySum(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int count = 0;
        for (int i = 0; i < nums.length; i ++) {
            int sum = 0;
            for (int j = i; j < nums.length; j ++) {
                sum += nums[j];
                if (sum == k) {
                    count ++;
                }
            }
        }
        return count;
    }

根據哈希表算法思路,編寫的算法代碼如下:

    public int subarraySum(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        HashMap<Integer, Integer> map = new HashMap<>();
        int count = 0, sum = 0;
        map.put(0, 1);
        for (int i = 0; i < nums.length; i ++) {
            sum += nums[i];
            if (map.containsKey(sum - k)) { // 和爲 sum - k 的數據與和爲 sum 的區間數的和即爲 k,這個區間的數即爲滿足題意的和爲 k 的連續的子數組的數
                count += map.get(sum - k);
            }
            // 保存和爲 sum 的數量
            map.put(sum, map.getOrDefault(sum, 0) + 1);
        }
        return count;
    }

如果你有疑問或更好的算法思路,歡迎留言交流!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章