Leetcode C++《热题 Hot 100-21》581.最短无序连续子数组
- 题目
给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
你找到的子数组应是最短的,请输出它的长度。
示例 1:
输入: [2, 6, 4, 8, 10, 9, 15]
输出: 5
解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。
说明 :
输入的数组长度范围在 [1, 10,000]。
输入的数组可能包含重复元素 ,所以升序的意思是<=。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路
- 方案1:排好序之后,时间复杂度是nlogn,最坏时间复杂度是n^2; 空间复杂度是n
- 方案2:时间复杂度n*n,空间复杂度O(1), 确定不在正确排序的最左边和最右边的边界,是方案1的优化方案,将元素两两比较,如果是逆序对,更新左右边界
- 方案3:使用栈,时间复杂度O(n),空间复杂度O(n),还是找边界:左边界用栈找,一直push,如果有下降的值x,就一直pop到比下降的值小,最后根据栈的size就可以得到左边界
- 方案4: 时间复杂度O(n),空间复杂度O(1),方案3的优化,不用栈了,思路是一样的,比如找左边界从左边开始遍历,变大不管,变小的index标记为x,变小的值记为xv,可能会有一个波动曲线,不断变大变小,我们要找那个全局从大变小的值里面的最小min xv,然后往回找到比min xv小的第一个出现的数字,就是左边界(两次遍历);找右边界同理
- 实现了方案1和方案4,请看下面!
- 代码
class Solution {
public:
//28ms方案1,48ms方案4,棒!立竿见影的优化
/*int findUnsortedSubarray(vector<int>& nums) {
vector<int> res;
res.assign(nums.begin(), nums.end());
sort(res.begin(),res.end());
int start = -1, end = -1;
for (int i = 0 ; i < nums.size(); i++) {
if (res[i] != nums[i]) {
start = i;
break;
}
}
for (int i = nums.size()-1 ; i >= 0; i--) {
if (res[i] != nums[i]) {
end = i;
break;
}
}
if (start == -1 && end == -1)
return 0;
if (start == -1)
return end + 1;
if (end == -1)
return nums.size()-start;
return end-start+1;
}*/
int findUnsortedSubarray(vector<int>& nums) {
int min_left;
int max_right;
int left_index = -1;
int right_index = -1;
int left_flag = false;
int right_flag = false;
for (int i = 0; i < nums.size()-1; i++) {
if (nums[i] > nums[i+1]) {
min_left = (left_flag == false)?nums[i+1]: min(min_left, nums[i+1]);
left_flag = true;
//cout << min_left << endl;
}
}
if (left_flag) {
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > min_left) {
left_index = i;
break;
}
}
}
//cout << left_index << endl;
for (int i = nums.size()-1; i > 0; i--) {
if (nums[i] < nums[i-1]) {
max_right = (right_flag == false)?nums[i-1]: max(max_right, nums[i-1]);
right_flag = true;
}
}
if (right_flag) {
for (int i = nums.size()-1; i >= 0; i--) {
if (nums[i] < max_right) {
right_index = i;
break;
}
}
}
//cout << right_index << endl;
if (left_flag == false && right_flag == false)
return 0;
if (left_flag == false)
return right_index + 1;
if (right_flag == false)
return nums.size()-left_index;
return right_index-left_index+1;
}
};