581. 最短無序連續子數組
給定一個整數數組,你需要尋找一個連續的子數組,如果對這個子數組進行升序排序,那麼整個數組都會變爲升序排序。
你找到的子數組應是最短的,請輸出它的長度。
示例 1:
輸入: [2, 6, 4, 8, 10, 9, 15] 輸出: 5 解釋: 你只需要對 [6, 4, 8, 10, 9] 進行升序排序,那麼整個表都會變爲升序排序。說明 :
- 輸入的數組長度範圍在 [1, 10,000]。
- 輸入的數組可能包含重複元素 ,所以升序的意思是<=。
解法一
//時間複雜度O(nlogn), 空間複雜度O(n)
class Solution {
public:
int findUnsortedSubarray(vector<int>& nums) {
vector<int> temp(nums);
sort(temp.begin(), temp.end());
int i = 0, j = nums.size() - 1;
while (i < j) {
if(nums[i] != temp[i] && nums[j] != temp[j]) break;
if(nums[i] == temp[i]) i++;
if(nums[j] == temp[j]) j--;
}
return i >= j ? 0 : j - i + 1;
}
};
解法二
//時間複雜度O(n), 空間複雜度O(1)
class Solution {
public:
int findUnsortedSubarray(vector<int>& nums) {
int len = nums.size();
int max = nums[0], min = nums[len - 1];
int start = 1, end = 0;
for(int i = 1; i < len; i++) {
if(nums[i] >= max) max = nums[i];//等於號不可少
else end = i;//當max > nums[i]
if(nums[len - 1 - i] <= min) min = nums[len - 1 - i];
else start = len - 1 - i;
}
return end - start + 1;
}
};
思路:
解法一,先構造一個相同的數組,排序,再從兩端開始向中間遍歷,比較與原數組不同的地方。
解法二,這個解法確實厲害。一開始有些難理解,建議找個例子人腦調試一下就懂了。
循環體內從左、右兩端開始同時遍歷,只看其中從左至右這一個方向的話,這個循環所做的,就是就標記end向右推到最終合適的位置(“合適”是指該標記右側所有元素都大於其左側元素,且右側元素爲增序);同理,反向是把標記start向左推。最終得到一個不合法序列的範圍,返回其長度。
要注意的是,對於一個從小到大的有序序列,它不會修改兩個標記,這時應該讓其返回1,這是我們讓start = 1, end = 0的原因。