1. 程式人生 > 其它 >尋找寫程式碼感覺(十四)之 新增功能的開發

尋找寫程式碼感覺(十四)之 新增功能的開發

和為 K 的子陣列

問題重述:

給你一個整數陣列 nums 和一個整數 k ,請你統計並返回該陣列中和為 k 的連續子陣列的個數

示例 1:

輸入:nums = [1,1,1], k = 2
輸出:2

示例 2:

輸入:nums = [1,2,3], k = 3
輸出:2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

問題分析:

一般看到陣列中的連續子陣列求和,我們會想到使用字首和

解法:

字首和

解題:

程式碼:
public static int subarraySum(int[] nums, int k) {
        // 定義一個字首和陣列
        int[] preNums = new int[nums.length+1];
        // 字首和陣列的第一個值為0
        preNums[0] = 0;
        // 為字首和陣列賦值
        for(int i = 1; i < preNums.length;i++){
            preNums[i] = preNums[i-1] + nums[i-1];
        }
        int count = 0;
        for(int left = 0;left < preNums.length;left++){
            for(int right = left+1;right < preNums.length;right++){
                if(preNums[right] - preNums[left] == k){
                    count += 1;
                }
            }
        }
        return count;
    }
	public static int subarraySum1(int[] nums,int k){
		int count = 0,pre = 0;
		Map<Integer,Integer> map = new HashMap<Integer,Integer>();
		map.put(0, 1);
		for(int num : nums) {
			pre += num;
			if(map.containsKey(pre - k)) {
				count += map.get(pre-k);
			}
			map.put(pre,map.getOrDefault(pre, 0)+1);
			
		}
		return count;
	}

程式碼解析:

前面一個方法是單純的字首和方法,時間複雜度為O(N),我們定義了一個字首和陣列,其中的每一個數組元素都對應了原來陣列的前n項和,接下來我們遍歷字首和陣列。我們先固定陣列的左邊界,讓左邊不動,然後陣列的右邊節不斷向右擴張,擴張一個,就將當前的值和k進行對比,如果相同,則count+1,不相同則右邊界擴張。如果右邊界到達了陣列的末尾,將左邊界右移一位,右邊界回到左邊界的起始位置,重新開始,知道左邊界遍歷到陣列的末尾,最後得到的count就是和為k的子陣列個數

第二個方法是對字首和方法的優化,使用雜湊表來幫助我們簡化了求子陣列和的過程。我們在遍歷陣列的時候,每一次都記錄陣列的字首和,雜湊表中以字首和為key,字首和出現的次數作為value存放資料。因為pre[j]-pre[i] = k,所以pre[i] = pre[j]-k

,所以我們可以用當前字首和-k的值代表此時有一個子陣列的和為k,因此我們只需要判斷雜湊表中有沒有pre[j]-k對應的資料就可以了,每一次遍歷一個結點都要對雜湊表進行更新。

總結:

字首和的適用範圍:在陣列中,當我們要求連續陣列的和的時候,我們就要考慮使用字首和。