leetcode連續數組系列

一、前綴和

560:和爲k的子數組

給定一個整數數組和一個整數 k,你需要找到該數組中和爲 k 的連續的子數>
組的個數。
示例 1 :
輸入:nums = [1,1,1], k = 2 輸出: 2 , [1,1] 與 [1,1] 爲兩種不同的情況。

這道題暴力的解法就是先保存數組的前綴和,然後遍歷差分,求所有和爲K的子數組,時間複雜度爲O(n^2)。

一次遍歷的解法:遍歷求前綴和,利用HashMap將所有前綴和的次數保存起來,遍歷到某個前綴和sum時,判斷map中是否存在sum-k,如果有,說明有連續數組的和爲k。最後將此前綴和次數+1存入map中。此解法時間複雜度爲o(n)。注意當前綴和sum==k時,sum-k=0,所以需要初始化map.put(0,1)。

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer,Integer> map = new HashMap<>();
        map.put(0,1);
        int sum = 0;
        int res = 0;
        for(int i = 0;i < nums.length;++i){
            sum+=nums[i];
            if(map.containsKey(sum-k))
                res+=map.get(sum-k);
            map.put(sum,map.getOrDefault(sum,0)+1);
        }
        return res;
    }
}

525. 連續數組

給定一個二進制數組, 找到含有相同數量的 0 和 1 的最長連續子數組(的長度)。

示例 1:
輸入: [0,1,1]
輸出: 2
說明: [0, 1] 是具有相同數量0和1的最長連續子數組。

這道題和上面那道題異曲同工,不過需要轉換一下思路,同樣用前綴和sum(i),不過遇到0加1,遇到1減1,若區間[i,j]的0,1數量相同,那麼sum(i-1)sum(j)前綴和相同,那麼長度就爲j-(i-1),因此我們需要map來保存的是前綴和所在的索引,此外,因爲題目求得是最長連續子數組,所以我們不能更新前綴和所在的索引,只保留第一次的索引。注意這道題map初始化應該爲map.put(0,-1)

    public int findMaxLength(int[] nums) {
        int res = 0;
        int sum = 0;
        Map<Integer,Integer> map = new HashMap<>();
        map.put(0,-1);
        for(int i = 0;i < nums.length;++i){
            sum+= nums[i]==0?1:-1;
            if(map.containsKey(sum)){
                res = Math.max(res,i-map.get(sum));
            }
            else{
                map.put(sum,i);
            }
        }
        return res;
    }

二、滑動窗口

1004. 最大連續1的個數 III

給定一個由若干 0 和 1 組成的數組 A,我們最多可以將 K 個值從 0 變成 1 。返回僅包含 1 的最長(連續)子數組的長度。
示例 1:
輸入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
輸出:6
解釋:
[1,1,1,0,0,1,1,1,1,1,1]
粗體數字從 0 翻轉到 1,最長的子數組長度爲 6。

這道題最直觀的解法就是依次嘗試將K個0轉換爲1的後的子串長度,先固定子串左邊位置left,然後滑動右窗口,遇到0則K--直到K爲-1。但是這樣的解法存在大量的重複計算,能否優化去掉一部分重複計算呢?

考慮到K爲-1時,窗口內的0的數量爲K,假設此時右指針位置爲right,左指針爲left,當left的下一位仍爲1時,窗口內的0的數量沒有變,所以連續長度肯定-1,所以不需要這部分的計算,因此下一次搜索時需要移動左指針來去掉一個0,這樣就會減少不需要的重複計算。

    public int longestOnes(int[] A, int K) {
        int left = 0, right = 0;
        int len = A.length;
        int res = 0;
        while(left<=right&&right<len){
            if(A[right]==0)
                K--;
            if(K < 0){
                res = Math.max(right-left,res);
                while(A[left]!=0)
                    left++;
                left++;
                K++;
            }
            right++;
            

        }
        return Math.max(right-left,res);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章