[LeetCode] 523. 連續的子數組和 ➕ 560. 和爲K的子數組

1 題目描述

  • 523. 連續的子數組和
    給定一個包含非負數的數組和一個目標整數 k,編寫一個函數來判斷該數組是否含有連續的子數組,其大小至少爲 2,總和爲 k 的倍數,即總和爲 n*k,其中 n 也是一個整數。

示例 1:

輸入: [23,2,4,6,7], k = 6
輸出: True
解釋: [2,4] 是一個大小爲 2 的子數組,並且和爲 6。

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

示例 1 :

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

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/subarray-sum-equals-k
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

2 解題思路

  • 523. 連續的子數組和
    方法1:暴力 [Time Limited Exceeded]
    暴力方法是很顯然的。我們考慮所有長度大於等於 2 的子數組,我們將子數組遍歷一遍求和,並判斷和是否是給定整數 k 的倍
    方法 2:使用累加和 [Accepted]
    可以在某種程度上優化暴力算法。如果我們用一個額外的 sum 數組保存數組的累積和,那麼 sum[i] 保存着到第 i 個元素位置的前綴和。

因爲,就如前面所述,我們考慮每一個子數組並求它的和。但是與剛剛不同的是,我們不會遍歷整個子數組來求和,我們只需要使用數組的前綴和。因此,求第 i 個數到第 j 個數,我們只需要求出 sum[j]−sum[i]+nums[i] 。

  • 560. 和爲K的子數組
    方法一 暴力 [超出時間限制]
    最簡單的方法是考慮給定 nums 數組的每個可能的子數組,找到每個子數組的元素總和,並檢查使用給定 k 獲得的總和是否相等。當總和等於 k 時,我們可以遞增用於存儲所需結果的 count。
    方法二 使用累計和 [通過]
    對於每個考慮的新子數組,我們不是每次都計算元素的總和,而是使用累積和數組 sum。然後,爲了計算位於兩個索引之間的元素之和,我們可以減去對應於兩個索引的累積和以直接獲得總和,而不是迭代子數組以獲得總和。

這個實現是基於累加和數組 sum,sum[i] 用於存儲 nums 的序號 0 到 (i−1) th之間元素的和,所以,爲了確定子數組 nums[i:j] 的元素總和,我們可以直接使用 sum[j+1]−sum[i],並可以通過 sum[j+1]−sum[i] 來得到子數組 nums[i:j] 的和。

三 兩道題目比較

官方題解都是給出了暴力法和累加和兩種解法,暴力法就真的比較暴力,三次嵌套循環解決問題,
對於累加和來說,就是利用一個數組去存儲它的累積和,這樣就可以索引對應相減就可以,而不用每次都迭代獲得總和,大大減少了時間複雜度。

兩道題目的兩種代碼基本都如出一轍,只是臨界條件不同,相似度+++

四解決代碼

  • 523. 連續的子數組和
    方法1:暴力 [Time Limited Exceeded]
public class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {

        for (int start = 0; start < nums.length - 1; start++) {
            for (int end = start + 1; end < nums.length; end++) {
                int sum = 0;
                for (int i = start; i <= end; i++)
                    sum += nums[i];
                if (sum == k || (k != 0 && sum % k == 0))
                    return true;
            }
        }
        return false;
    }
}

方法 2:使用累加和 [Accepted]

public class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        int[] sum = new int[nums.length];
        sum[0] = nums[0];
        for (int i = 1; i < nums.length; i++)
            sum[i] = sum[i - 1] + nums[i];
        for (int start = 0; start < nums.length - 1; start++) {
            for (int end = start + 1; end < nums.length; end++) {
                int summ = sum[end] - sum[start] + nums[start];
                if (summ == k || (k != 0 && summ % k == 0))
                    return true;
            }
        }
        return false;
    }
}
  • 560. 和爲K的子數組
    方法一 暴力 [超出時間限制]
public class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0;
        for (int start = 0; start < nums.length; start++) {
            for (int end = start + 1; end <= nums.length; end++) {
                int sum = 0;
                for (int i = start; i < end; i++)
                    sum += nums[i];
                if (sum == k)
                    count++;
            }
        }
        return count;
    }
}

方法二 使用累計和 [通過]

public class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0;
        int[] sum = new int[nums.length + 1];
        sum[0] = 0;
        for (int i = 1; i <= nums.length; i++)
            sum[i] = sum[i - 1] + nums[i - 1];
        for (int start = 0; start < nums.length; start++) {
            for (int end = start + 1; end <= nums.length; end++) {
                if (sum[end] - sum[start] == k)
                    count++;
            }
        }
        return count;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章