1.算法題目
給定一個整數數組和一個整數 k,你需要找到該數組中和爲 k 的連續的子數組的個數。
示例 1 :
輸入:nums = [1,1,1], k = 2
輸出: 2 , [1,1] 與 [1,1] 爲兩種不同的情況。
說明 :
數組的長度爲 [1, 20,000]。
數組中元素的範圍是 [-1000, 1000] ,且整數 k 的範圍是 [-1e7, 1e7]。
2.算法思路
- 暴力法:考慮給定數組 sums 的每個可能的子數組,找到每個子數組的總和,並檢查總和是否等於 k,等於時遞增用於記錄所需結果的 count;時間複雜度爲 O(n^3),空間複雜度爲 O(1),超出時間限制;
- 使用累計和:計算數組的每個數字開始到累加後面每個數字的和,遇到和爲 k時, count 加1;需要兩層循環遍歷,時間複雜度爲 O(n^2),空間複雜度爲 O(1);
- 使用哈希表:使用一個哈希表 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;
}
如果你有疑問或更好的算法思路,歡迎留言交流!!!