阿里18道常見的MySQL面試題,含解析
阿新 • • 發佈:2020-10-23
1.問題描述
我們把陣列 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
。
示例 1:
輸入:[2,1,4,7,3,2,5]
輸出:5
解釋:最長的 “山脈” 是 [1,4,7,3,2],長度為 5。
示例 2:
輸入:[2,2,2]
輸出:0
解釋:不含 “山脈”。
提示:
0 <= A.length <= 10000
0 <= A[i] <= 10000
2.求解
暴力法列舉山頂
- 列舉陣列
[1,length-1]
的元素,對於每個元素,判斷其是否能向左右延伸成為山脈,最後的右延伸距離減去左延伸距離+1即為當前山頂的長度
程式碼如下
/* * 執行用時:4 ms, 在所有 Java 提交中擊敗了22.60% 的使用者 * 記憶體消耗:39.5 MB, 在所有 Java 提交中擊敗了83.89% 的使用者 * */ public int longestMountain(int[] A) { int left, right; int maxAns = 0; //列舉每一個可能是山頂的點 for (int i = 1; i < A.length - 1; i++) { int ans; int pre = A[i]; left = i; right = i; //判斷是否能成為山頂(左右兩側是否小於它) if (A[i - 1] < pre && A[right + 1] < pre) { left = i - 1; right = i + 1; //判斷左側山腳 while (left > 0 && A[left] < pre) { pre = A[left]; left--; } if (A[left] >= pre) left++; //修正左側山腳位置 pre = A[i]; //判斷右側山腳 while (right < A.length - 1 && A[right] < pre) { pre = A[right]; right++; } } if (A[right] >= pre) right--; //修正右側側山腳位置 ans = right - left + 1; maxAns = Math.max(ans, maxAns); //計算山脈總長度 } return maxAns; }
- 時間複雜度平方級,執行用時較長
動態規劃
- 新建一個大小等於A陣列長度的陣列left,left陣列內部元素初始值都為0
- 用
left[i]
來表示A[i]
最多能向左側擴充套件的長度,如果A[i] > A[i-1]
則表示A[i]可以向左側延伸到A[i-1]
,所以有left[i] = left[i-1] + 1
- 同樣我們使用陣列
right[i]來表示A[i]
最多能向右側擴充套件的長度,只不過這次是從右側倒序遍歷 - 最後我們遍歷每一個可能是山頂的位置
A[i]
,計算它向左側和右側延伸的距離和即可
程式碼如下
/* * 執行用時:3 ms, 在所有 Java 提交中擊敗了69.39% 的使用者 * 記憶體消耗:38.8 MB, 在所有 Java 提交中擊敗了100.00% 的使用者 * */ public int longestMountain(int[] A) { int len = A.length; if (len == 0) { return 0; } //對於每個A[i],記錄下能夠向左延伸到的距離 int[] left = new int[len]; for (int i = 1; i < len; i++) { left[i] = A[i - 1] >= A[i] ? 0 : left[i - 1] + 1; } //對於每個A[i],記錄下能夠向右延伸到的距離 int[] right = new int[len]; for (int i = len - 2; i >= 0; i--) { right[i] = A[i + 1] >= A[i] ? 0 : right[i + 1] + 1; } //對於每個可能成為山頂的位置,判斷是能否成為山脈 int maxAns = 0; for (int i = 1; i < len - 1; i++) { //若是山脈,則計算山脈的長度 if (left[i] > 0 && right[i] > 0) { maxAns = Math.max(maxAns, left[i] + right[i] + 1); } } return maxAns; }
-
時間複雜度:O(n),其中 n是陣列 AAA 的長度。
-
空間複雜度:O(n),即為陣列 left 和 right 需要使用的空間。
雙指標列舉山腳位置
- 定義指標
left、right
,固定left位置,每次向右移動right指標,判斷能否成為山脈 - 對於left的情況分析
A[left] > A[left + 1]
,不構成左側山腳,令left = right
,右側山腳成為下一次列舉左側山腳的起點- 1判斷通過,證明存在左側山腳,移動right指標延伸左側山腳
- 存在右側山腳,即
A[right] > A[right+1]
,移動right指標延伸右側山腳,完畢後判斷山脈長度,即當前山脈長度 = right - left + 1
- 不存在右側山腳,因為right = left + 1,說明當前right所在的位置也不可能成為左側山腳,right指標右移一位,令
left = right
,右側山腳成為下一次列舉左側山腳的起點
- 存在右側山腳,即
程式碼如下
/*
* 執行用時:2 ms, 在所有 Java 提交中擊敗了99.84% 的使用者
* 記憶體消耗:39.7 MB, 在所有 Java 提交中擊敗了75.75% 的使用者
* */
public int longestMountain(int[] A) {
int n = A.length;
int left = 0;
int maxAns = 0;
//少於3個點不構成山脈
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++;
}
//所有條件滿足,構成山脈,判斷山脈長度
maxAns = Math.max(maxAns, right - left + 1);
} else {
right++;
}
}
//從右側山腳開始判斷是否是下一個左側山腳
left = right;
}
return maxAns;
}
-
時間複雜度:O(n),其中 n 是陣列 A 的長度。
-
空間複雜度:O(1)。