置頂

我的 VPython 教學文件 (HackMD 版本)

VPython 教學文件目錄 安裝及測試 基本語法 等速度直線運動 自由落下 終端速度 水平抛射 使用For迴圈計算水平抛射資料 斜向抛射 圓周運動 簡諧運動 單擺 木塊彈簧系統分離 重力及簡諧 行星運動 相疊木塊 雙重簡諧運動 一維彈性碰撞 ...

熱門文章

2026年9月17日 星期四

LeetCode 解題筆記:1477. Find Two Non-overlapping Sub-arrays Each With Target Sum

作者:王一哲
日期:2026年9月17日


LeetCode 題目連結:1477. Find Two Non-overlapping Sub-arrays Each With Target Sum

解題想法


中等難度題,題目給一個陣列 $arr$ 與一個整數 $target$,要找出 $2$ 個不重疊、加總等於 $target$ 的連續子陣列,回傳這兩個子陣列長度相加的最小值。題目下方有提示:
  1. 建立一個陣列 $prefix$,$prefix[i]$ 代表在 $i$ 之前結束、加總等於 $target$ 的連續子陣列最短長度。再建立一個陣列 $suffix$,$suffix[i]$ 代表從 $i$ 開始、加總等於 $target$ 的連續子陣列最短長度。
  2. 檢查 $i = 0$ 到 $i = n-1$,找出 $prefix[i] + suffix[i]$ 的最小值。
  3. 如果在建立 $prefix, suffix$ 時遇到困難,可以先將所有的值都設定成無窮大,分別先找出加總等於 $target$ 的前綴、後綴連續子陣列長度,之後再轉換成最短長度。
基本上按照以上的提示寫程式碼就可以過關了。

Python 程式碼


Runtime: 260 ms, beats 29.61%. Memory: 31.07 MB, beats 83.24%.
class Solution:
    def minSumOfLengths(self, arr: List[int], target: int) -> int:
        n = len(arr)  # 長度
        maxn = n + 1  # 長度加 1,答案不可能大於 n
        
        # 1. 用滑動視窗找 prefix
        prefix = [maxn] * n  # prefix[i] 代表於 i-1 結束,子陣列和等於 target 的長度
        rsum, left = 0, 0
        for right in range(n - 1):
            rsum += arr[right]
            while left < right and rsum > target:
                rsum -= arr[left]
                left += 1
            if rsum == target:
                length = right - left + 1
                prefix[right + 1] = min(prefix[right + 1], length)
        
        # 2. 再將 prefix[i] 改成從左往右找,於 i-1 結束、子陣列和等於 target 的最短長度
        pmin = maxn
        for i in range(1, n):
            if prefix[i] < pmin:
                pmin = prefix[i]
            elif prefix[i] > pmin:
                prefix[i] = pmin
        
        # 3. 用滑動視窗找 prefix
        suffix = [maxn] * n  # suffix[i] 代表於 i 結束,後綴子陣列和等於 target 的長度
        lsum, ri = 0, n-1
        for le in range(n-1, -1, -1):
            lsum += arr[le]
            while ri > le and lsum > target:
                lsum -= arr[ri]
                ri -= 1
            if lsum == target:
                length = ri - le + 1
                suffix[le] = min(suffix[le], length)
        
        # 4. 再將 suffix[i] 改成從右往左找,於 i 結束、後綴子陣列和等於 target 的最短長度
        smin = maxn
        for i in range(n-1, -1, -1):
            if suffix[i] < smin:
                smin = suffix[i]
            elif suffix[i] > smin:
                suffix[i] = smin

        # 5. 答案預設為 maxn * 2,從 i = 0 ~ n-1 找 prefix[i] + suffix[i] 的最小值
        ans = maxn * 2
        for i in range(n):
            if prefix[i] < maxn and suffix[i] < maxn:
                ans = min(ans, prefix[i] + suffix[i])
        # 如果 ans 小於預設值,回傳 ans;反之回傳 -1
        return ans if ans < maxn * 2 else -1


Runtime: 207 ms, beats 36.31%. Memory: 31.22 MB, beats 57.54%.
class Solution:
    def minSumOfLengths(self, arr: List[int], target: int) -> int:
        n = len(arr)  # 長度
        maxn = n + 1  # 長度加 1,答案不可能大於 n
        
        # 1. 用滑動視窗找 prefix
        prefix = [maxn] * n  # prefix[i] 代表於 i-1 結束,子陣列和等於 target 的最短長度
        pmin, rsum, left = maxn, 0, 0
        for right in range(n - 1):
            rsum += arr[right]
            while left < right and rsum > target:
                rsum -= arr[left]
                left += 1
            if rsum == target:
                pmin = min(pmin, right - left + 1)
            prefix[right + 1] = pmin
        
        # 2. 用滑動視窗找 prefix
        suffix = [maxn] * n  # suffix[i] 代表於 i 結束,後綴子陣列和等於 target 的最短長度
        smin, lsum, ri = maxn, 0, n-1
        for le in range(n-1, -1, -1):
            lsum += arr[le]
            while ri > le and lsum > target:
                lsum -= arr[ri]
                ri -= 1
            if lsum == target:
                smin = min(smin, ri - le + 1)
            suffix[le] = smin
        
        # 3. 答案預設為 maxn * 2,從 i = 0 ~ n-1 找 prefix[i] + suffix[i] 的最小值
        ans = maxn * 2
        for i in range(n):
            if prefix[i] < maxn and suffix[i] < maxn:
                ans = min(ans, prefix[i] + suffix[i])
        # 如果 ans 小於預設值,回傳 ans;反之回傳 -1
        return ans if ans < maxn * 2 else -1


C++ 程式碼


Runtime: 18 ms, beats 50.26%. Memory: 92.38 MB, beats 47.68%.
class Solution {
public:
    int minSumOfLengths(vector<int>& arr, int target) {
        int n = (int)arr.size();  // 長度
        int maxn = n + 1;  // 長度加 1,答案不可能大於 n
        
        /* 1. 用滑動視窗找 prefix */
        vector<int> prefix (n, maxn);  // prefix[i] 代表於 i-1 結束,子陣列和等於 target 的長度
        int rsum = 0, left = 0;
        for(int right = 0; right < n-1; right++) {
            rsum += arr[right];
            while(left < right && rsum > target) {
                rsum -= arr[left];
                left++;
            }
            if (rsum == target) {
                int length = right - left + 1;
                prefix[right + 1] = min(prefix[right + 1], length);
            }
        }
        
        /* 2. 再將 prefix[i] 改成從左往右找,於 i-1 結束、子陣列和等於 target 的最短長度 */
        int pmin = maxn;
        for(int i = 1; i < n; i++) {
            if (prefix[i] < pmin) {
                pmin = prefix[i];
            } else if (prefix[i] > pmin) {
                prefix[i] = pmin;
            }
        }
        
        /* 3. 用滑動視窗找 prefix */
        vector<int> suffix (n, maxn);  // suffix[i] 代表於 i 結束,後綴子陣列和等於 target 的長度
        int lsum = 0, ri = n-1;
        for(int le = n-1; le >= 0; le--) {
            lsum += arr[le];
            while(ri > le && lsum > target) {
                lsum -= arr[ri];
                ri--;
            }
            if (lsum == target) {
                int length = ri - le + 1;
                suffix[le] = min(suffix[le], length);
            }
        }

        /* 4. 再將 suffix[i] 改成從右往左找,於 i 結束、後綴子陣列和等於 target 的最短長度 */
        int smin = maxn;
        for(int i = n-1; i >= 0; i--) {
            if (suffix[i] < smin) {
                smin = suffix[i];
            } else if (suffix[i] > smin) {
                suffix[i] = smin;
            }
        }

        /* 5. 答案預設為 maxn * 2,從 i = 0 ~ n-1 找 prefix[i] + suffix[i] 的最小值 */
        int ans = maxn * 2;
        for(int i = 0; i < n; i++) {
            if (prefix[i] < maxn && suffix[i] < maxn) {
                ans = min(ans, prefix[i] + suffix[i]);
            }
        }
        // 如果 ans 小於預設值,回傳 ans;反之回傳 -1
        return (ans < maxn * 2 ? ans : -1);
    }
};


Runtime: 13 ms, beats 55.15%. Memory: 92.37 MB, beats 47.68%.
class Solution {
public:
    int minSumOfLengths(vector<int>& arr, int target) {
        int n = (int)arr.size();  // 長度
        int maxn = n + 1;  // 長度加 1,答案不可能大於 n
        
        /* 1. 用滑動視窗找 prefix */
        vector<int> prefix (n, maxn);  // prefix[i] 代表於 i-1 結束,子陣列和等於 target 的最短長度
        int pmin = maxn, rsum = 0, left = 0;
        for(int right = 0; right < n-1; right++) {
            rsum += arr[right];
            while(left < right && rsum > target) {
                rsum -= arr[left];
                left++;
            }
            if (rsum == target) {
                int length = right - left + 1;
                if (length < pmin) {
                    pmin = length;
                }
            }
            prefix[right + 1] = pmin;
        }
        
        /* 2. 用滑動視窗找 prefix */
        vector<int> suffix (n, maxn);  // suffix[i] 代表於 i 結束,後綴子陣列和等於 target 的最短長度
        int smin = maxn, lsum = 0, ri = n-1;
        for(int le = n-1; le >= 0; le--) {
            lsum += arr[le];
            while(ri > le && lsum > target) {
                lsum -= arr[ri];
                ri--;
            }
            if (lsum == target) {
                int length = ri - le + 1;
                if (length < smin) {
                    smin = length;
                }
            }
            suffix[le] = smin;
        }

        /* 3. 答案預設為 maxn * 2,從 i = 0 ~ n-1 找 prefix[i] + suffix[i] 的最小值 */
        int ans = maxn * 2;
        for(int i = 0; i < n; i++) {
            if (prefix[i] < maxn && suffix[i] < maxn) {
                if (prefix[i] + suffix[i] < ans) {
                    ans = prefix[i] + suffix[i];
                }
            }
        }
        // 如果 ans 小於預設值,回傳 ans;反之回傳 -1
        return (ans < maxn * 2 ? ans : -1);
    }
};


沒有留言:

張貼留言