题目描述
给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的 最短 子数组,并输出它的长度。
解题思路一:
调用 sort 对nums数组进行排序,然后比较对应位置的值,找出符合题意的最短子数组即可。时间复杂度为 O(nlogn)
AC代码
class Solution {
public:
int findUnsortedSubarray(vector<int>& nums) {
int len = nums.size(), ans = 0;
vector<int>v;
for(auto i : nums) v.push_back(i);
sort(nums.begin(), nums.end());
int left = len - 1, right = 0;
for(int i = 0; i < len; i++) {
if(nums[i] != v[i]) {
left = i;
break;
}
}
for(int i = len - 1; i >= 0; i--) {
if(nums[i] != v[i]) {
right = i;
break;
}
}
if(left >= right) return 0;
return right - left + 1;
}
};
解题思路二:
看了网上一位大佬的解法后,对这道题瞬间有了一种恍然大悟的感觉,无序进行排序。
我们可以假设吧这个数组分成三段,左段和右段是标准的按照升序排序好的数组,中间一段的数组虽然是无序的,但是满足中间段的最大值小于右段的最小值,最大值大于左段的最大值。
那么我们的任务就变成了找中间段的左右边界,我们分别定义为 left 和 right.,从左右两头开始遍历。
从左到右维护的是最大值 Max, 在进入右段之前,那么遍历到的nums[i] 的值都是小于Max的,而 right 就是遍历中小于Max元素的边界
同理,从右到左维护的是最小值 Min,在进入左段之前,那么遍历到的nums[i] 的值都是大于 Min 的,而 left 就是遍历中大于 Min元素的边界
时间复杂度为 O(n)
AC代码
class Solution {
public:
int findUnsortedSubarray(vector<int>& nums) {
int len = nums.size();
int left = 0, right = -1, Max = nums[0], Min = nums[len-1];
for(int i = 0; i < len; i++) {
if(nums[i] >= Max) Max = nums[i];
else right = i;
if(nums[len-i-1] <= Min) Min = nums[len - i - 1];
else left = len - i - 1;
}
return right - left + 1;
}
};