多執行緒-2
1.題目描述
給定一個整數陣列,你需要尋找一個連續的子陣列,如果對這個子陣列進行升序排序,那麼整個陣列都會變為升序排序。
你找到的子陣列應是最短的,請輸出它的長度。
示例 1:
輸入: [2, 6, 4, 8, 10, 9, 15]
輸出: 5
解釋: 你只需要對 [6, 4, 8, 10, 9] 進行升序排序,那麼整個表都會變為升序排序。
2.題解
2.1 暴力
public int findUnsortedSubarray(int[] nums) { int res = nums.length; for (int i = 0; i < nums.length; i++) { for (int j = i; j <= nums.length; j++) { int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE, prev = Integer.MIN_VALUE; for (int k = i; k < j; k++) { min = Math.min(min, nums[k]); max = Math.max(max, nums[k]); } if ((i > 0 && nums[i - 1] > min) || (j < nums.length && nums[j] < max)) continue; int k = 0; while (k < i && prev <= nums[k]) { prev = nums[k]; k++; } if (k != i) continue; k = j; while (k < nums.length && prev <= nums[k]) { prev = nums[k]; k++; } if (k == nums.length) { res = Math.min(res, j - i); } } } return res; }
陣列[2, 6, 4, 8, 10, 9, 15]
的最短無序連續子陣列為nums[1:6]
,即[6, 4, 8, 10, 9]
。
nums[0]
和nums[6]
是升序的。子陣列nums[1:6]
的最小值大於nums[0]
,最大值小於nums[6]
。所以,只要對nums[1:6]
這個子陣列進行升序排序,那麼整個陣列都會變為升序排序。
解釋程式碼:
通過兩層迴圈遍歷所有可能的子序列。
遍歷到子序列[2, 6, 4]
時,由於4<6
,所以需要對[2, 6, 4]
排序。
同理,遍歷到子序列[2, 6, 4, 8, 10, 9]
時,由於9<10
,也需要對[2, 6, 4, 8, 10, 9]
排序。
if ((i > 0 && nums[i - 1] > min) || (j < nums.length && nums[j] < max)) continue;
下面這部分程式碼用於檢查nums[j:n−1]
是否是升序的,如果nums[j:n−1]
是升序的,那麼k == nums.length
,就可以求子陣列nums[i:j]
的長度。
int k = 0;
// ...
k = j;
while (k < nums.length && prev <= nums[k]) {
prev = nums[k];
k++;
}
if (k == nums.length) {
res = Math.min(res, j - i);
}
下面這部分程式碼用於檢查nums[0:i−1]
和nums[j:n−1]
是否是升序的。
int k = 0; while (k < i && prev <= nums[k]) { prev = nums[k]; k++; } // ... k = j; while (k < nums.length && prev <= nums[k]) { prev = nums[k]; k++; } if (k == nums.length) { res = Math.min(res, j - i); }
最後可以求得全域性最短無序連續子陣列。
2.2 更好的暴力
// [2, 6, 4, 8, 10, 9, 15]
public int findUnsortedSubarray(int[] nums) {
int l = nums.length, r = 0;
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] < nums[i]) {
r = Math.max(r, j);
l = Math.min(l, i);
}
}
}
return r - l < 0 ? 0 : r - l + 1;
}
顯然nums[0]
在陣列中的正確位置上。
當i = 1, j = 2
時,由於nums[1]<nums[2](即6<4)
,所以nums[1]
不在陣列中的正確位置上,更新無序子陣列的左邊界為1
,右邊界為2
。
當i = 4, j = 5
時,同理,由於nums[4]<nums[5]
,更新無序子陣列的左邊界為1
,右邊界為5
。
實際上,對於陣列[2, 6, 4, 8, 10]
,對其子陣列[6, 4]
進行升序排序即可。而對於[2, 6, 4, 8, 10, 9]
,需要對其子陣列[6, 4, 8, 10, 9]
進行升序排序。
注意到對於陣列[15, 4, 6, 8, 9, 10, 2]
,即使其子陣列[4, 6, 8, 9, 10]
是升序排序的,也需要對整個陣列進行升序排序。
2.3 排序
// [2, 6, 4, 8, 10, 9, 15]
public int findUnsortedSubarray(int[] nums) {
int[] snums = nums.clone();
Arrays.sort(snums);
int start = snums.length, end = 0;
for (int i = 0; i < snums.length; i++) {
if (snums[i] != nums[i]) {
start = Math.min(start, i);
end = Math.max(end, i);
}
}
return (end - start >= 0 ? end - start + 1 : 0);
}
對原陣列進行升序排序後,對比原陣列和排序後的陣列,如果某個位置上的元素不相等,說明原陣列中該位置的元素不在正確的位置上。
2.4 使用棧
// [2, 6, 4, 8, 10, 9, 15]
public int findUnsortedSubarray(int[] nums) {
Stack < Integer > stack = new Stack < Integer > ();
int l = nums.length, r = 0;
for (int i = 0; i < nums.length; i++) {
while (!stack.isEmpty() && nums[stack.peek()] > nums[i])
l = Math.min(l, stack.pop());
stack.push(i);
}
stack.clear();
for (int i = nums.length - 1; i >= 0; i--) {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i])
r = Math.max(r, stack.pop());
stack.push(i);
}
return r - l > 0 ? r - l + 1 : 0;
}
注意到對於陣列[6, 2, 4, 8, 10, 15, 9]
,需要對整個陣列進行升序排序,因為nums[0]
和nums[6]
都不在正確的位置上。
2.5 不使用額外空間
// [2, 6, 4, 8, 10, 9, 15]
public int findUnsortedSubarray(int[] nums) {
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
boolean flag = false;
for (int i = 1; i < nums.length; i++) {
if (nums[i] < nums[i - 1])
flag = true;
if (flag)
min = Math.min(min, nums[i]);
}
flag = false;
for (int i = nums.length - 2; i >= 0; i--) {
if (nums[i] > nums[i + 1])
flag = true;
if (flag)
max = Math.max(max, nums[i]);
}
int l, r;
for (l = 0; l < nums.length; l++) {
if (min < nums[l])
break;
}
for (r = nums.length - 1; r >= 0; r--) {
if (max > nums[r])
break;
}
return r - l < 0 ? 0 : r - l + 1;
}
注意到nums[0]
和nums[6]
都在正確的位置上了,於是考慮子陣列[6, 4, 8, 10, 9]
。
由於6<4
和10<9
,所以min
為4
,max
為10
。
在無序子陣列中,其最小元素應該放到該陣列的第一個位置,其最大元素應該放到該陣列的最後一個位置。
因此,第一個大於4
的元素的位置是無序子陣列的第一個位置,第一個小於10
的元素的位置是無序子陣列的最後一個位置。
參考: