累加和等於num的最長子數組的長度

1. 累加和等於num的最長子數組的長度(有負數)

在這裏插入圖片描述
:數組元素可爲負數

思路:求子數組問題,就是依次考慮數組中每一位元素之前的數組的情況
比如說arr = {7,3,2,1,1,7,7},依次考慮數組範圍(0-i)中,任意元素開始,以arr[i]結尾的子數組是否符合條件。比如說i=0時,子數組{7}符合條件;i=4時,子數組{3,2,1,1}符合條件。

假設遍歷到i位置,數組元素從0加到i的值爲sum,只需要求i之前的數組中,是否出現過和爲sum-num的情況。例如,arr = {9,8,3,2,1,1,7,7},num=7,當遍歷到i=5的時候,sum=24,此時sum-num=24-7=17。因爲當i=1時,sum=17,所以下標從2到5,數組元素之和肯定爲sum。

public static int maxLength(int[] arr, int k) {
    if (arr == null || arr.length == 0) {
        return 0;
    }
    HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
    map.put(0, -1); // important
    int len = 0;
    int sum = 0;
    for (int i = 0; i < arr.length; i++) {
        sum += arr[i];
        if (map.containsKey(sum - k)) {
            len = Math.max(i - map.get(sum - k), len);
        }
        if (!map.containsKey(sum)) {
            map.put(sum, i);
        }
    }
    return len;
}

2. 累加和等於num的最長子數組的長度(無負數)

題目;給定一個數組arr, 全是正數; 一個整數aim, 求累加和等於aim的, 最長子數組, 要求額外空間複雜度O(1), 時間複雜度O(N)

思路:可以使用雙指針,一個在左,一個在右,形成一個窗口區域。當窗口中的值小於aim時,窗口右邊界擴大。當窗口中的值大於或等於aim時,由於數組中全爲正數,所以窗口右邊界再擴大,窗口中的值會大於aim。所以此時需要窗口左邊界右移。當窗口右邊界到達數組最後一個元素,且窗口中的值小於aim,返回結果。

數組中有負數和無負數的區別

窗口擴大,窗口內的累加和一定增加,窗口縮小,窗口內的累加和一定減小。

如有數組arr={7,8,-8},aim=7,當窗口右邊界移動到0時,窗口內的值已經是7了,這時候窗口會右移。但是,其實最長的子數組爲{7,8,-8}。所以有負數時,不能用此方法。

public static int getMaxLength(int[] arr, int k) {
    if (arr == null || arr.length == 0 || k <= 0) {
        return 0;
    }
    int L = 0;
    int R = 0;
    int sum = arr[0];
    int len = 0;
    while (R < arr.length) {
        if (sum == k) {
            len = Math.max(len, R - L + 1);
            sum -= arr[L++];//窗口左邊界右移
        } else if (sum < k) {
            R++;//當前窗口內的值小於aim,窗口右邊界右移,擴大窗口
            if (R == arr.length) {
                break;
            }
            sum += arr[R];
        } else {//當前窗口內的值大於aim,窗口左邊界右移
            sum -= arr[L++];
        }
    }
    return len;
}

3. 累加和小於等於num的最長子數組的長度

題目:給定一個數組arr, 值可正, 可負, 可0; 一個整數aim, 求累加和小於等於aim的, 最長子數組, 要求時間複雜度O(N)

思考:這一題要求小於等於,且數組元素有負數。就不能使用雙指針來構造滑動窗口了。因爲給定數組中有負數,在窗口擴大,窗口內的值不一定增大;窗口縮小,窗口內的值不一定減小。

思路:設計兩個數組max_summax_sum_index,長度爲給定數組的長度。數組元素max_sum[i]表示以arr[i]開頭,累加和最小的最長子數組的累加和;數組元素max_sum_index[i]與數組元素max_sum[i]相對應,表示以arr[i]開頭,累加和最小的最長子數組的右邊界下標

通過反向遍歷數組,得到數組max_summax_sum_index

例如,有數組arr={6,5,1,7,2,-6,-3,4,3,-2,1},aim=6,則數組max_summax_sum_index的情況如下所示
在這裏插入圖片描述

然後根據數組max_sum_index可將元素組劃分成幾個子數組。
在這裏插入圖片描述

可以將原數組看成如下數組,該數組中肯定不會出現負數,所以可以對其進行滑動窗口操作。
在這裏插入圖片描述

滑動窗口,遍歷過程中,滿足條件的子數組如下(自動捨棄長度更小的子數組組合)
在這裏插入圖片描述
然後分別計算對應的長度即可。第三個組合對應的數組爲{1,7,2,-6,-3,4,3,-2},長度爲8。

class Solution_MaxLength3{
    public static int maxLengthAwesome(int[] arr, int aim) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int[] max_sum = new int[arr.length];
        int[] max_sum_index = new int[arr.length];
        max_sum[arr.length - 1] = arr[arr.length - 1];
        max_sum_index[arr.length - 1] = arr.length - 1;
        for (int i = arr.length - 2; i >= 0; i--) {
            if (max_sum[i + 1] < 0) {
                max_sum[i] = arr[i] + max_sum[i + 1];
                max_sum_index[i] = max_sum_index[i + 1];
            } else {
                max_sum[i] = arr[i];
                max_sum_index[i] = i;
            }
        }
        int sum = 0;
        int len = 0;
        int start = 0;//窗口左邊界
        int end = 0;//窗口右邊界
        int next = 0;//要加進窗口的子數組中的第一個元素下標
        while(start < arr.length){
            while(next < arr.length && sum + max_sum[next] <= aim){
                sum += max_sum[next];
                end = max_sum_index[next];
                next = end + 1;
            }
            len = Math.max(len, next - start);
            //窗口左邊界右移
            if(end > start){
                sum -= max_sum[start];
            }else{//如果end == start,則有以後sum值爲0
                sum = 0;
            }
            start = max_sum_index[start] + 1;
        }
        return len;
    }

    public static void main(String[] args) {
        int[] arr = {6,5,1,7,2,-6,-3,4,3,-2,3};
        System.out.println(maxLengthAwesome(arr, 6));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章