1. 程式人生 > 實用技巧 >[leetCode]845. 陣列中的最長山脈

[leetCode]845. 陣列中的最長山脈

csdn:https://blog.csdn.net/renweiyi1487/article/details/109270033
原題地址:https://leetcode-cn.com/problems/longest-mountain-in-array

我們把陣列 A 中符合下列屬性的任意連續子陣列 B 稱為 “山脈”:

B.length >= 3
存在 0 < i < B.length - 1 使得 B[0] < B[1] < ... B[i-1] < B[i] > B[i+1] > ... > B[B.length - 1]
(注意:B 可以是 A 的任意子陣列,包括整個陣列 A。)

給出一個整數陣列 A,返回最長 “山脈” 的長度。

如果不含有 “山脈” 則返回 0。

動態規化

 由於從左側山腳到山頂,與從右側山腳到山頂是嚴格單調遞增的所以可以使用動態規化。
 另$left[i]$表示$A[i]$左側可以擴充套件的數量,$right[i]$表示$A[i]$右側可以擴充套件的數量,

  • 如果$A[i] > A[i-1]$ 那麼$left[i]=left[i-1]+1$;如果$i=0則left[i]=0$

  • 如果$A[i] > A[i+1]$ 那麼$right[i]=right[i+1]+1$;如果$i=n-1則right[i]=0$

計算出所有的$left[],right[]$後就可以列舉山頂,但是需要注意只有當$left[i] > 0 並且 right[i] >0$時A[i]才是山頂。

class Solution {
    public int longestMountain(int[] A) {
        int n = A.length;
        if (n == 0) {
            return 0;
        }
        // left[i] 表示A[i]左側最多能擴充套件的數目
        int[] left = new int[n];
        for (int i = 1; i < n; i++) {
            left[i] = A[i] > A[i-1] ? left[i-1]+1 : 0;
        }
        // right[i] 表示A[i]右側最多能擴充套件的數目
        int[] right = new int[n];
        for (int i = n-2; i >=0; i--) {
            right[i] = A[i] > A[i+1] ? right[i+1] + 1 : 0;
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            if (left[i] > 0 && right[i] >0) {
                ans = Math.max(ans, left[i] + right[i] + 1);
            }
        }
        return ans;
    }
}

雙指標

定義一個左指標初始值為0指向山腳,每次固定left時需要保證:

  • left + 2 < n 因為山脈的長度至少為三
  • 然後設定right 指標為left+1,如果left在山腳則控制right指標爬山
  • 如果right指標爬到的是山頂則控制right指標下山,然後計算山脈長度,如果right指標爬到的不是山頂則讓right指標+1,每尋找一次山腳就要重新固定left
class Solution {
    public int longestMountain(int[] A) {
        int n = A.length;
        if (n == 0) {
            return 0;
        }
        int left = 0, ans = 0;
        while (left + 2 < n) {
            int right = left + 1;
            if (A[left] < A[left+1]) {
                while (right + 1 < n && A[right] < A[right+1]) {
                    right++;
                }
                if (right + 1 < n && A[right] > A[right+1]) {
                    while (right + 1 < n && A[right] > A[right+1]) {
                        right++;
                    }
                    ans = Math.max(ans, right-left+1);
                } else {
                    right++;
                }
            }
            left = right;
        }
        return ans;
    }
}