581. 最短无序连续子数组
题目描述:
给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
你找到的子数组应是最短的,请输出它的长度。
示例 1:
输入: [2, 6, 4, 8, 10, 9, 15]
输出: 5
解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。
说明 :
输入的数组长度范围在 [1, 10,000]。
输入的数组可能包含重复元素 ,所以升序的意思是<=。
思想1:
将数组nums 进行排序,记为 sort_nums。然后我们比较 nums 和 sort_nums的元素来决定最左边和最右边不匹配的元素。它们之间的子数组就是要求的最短无序子数组。
代码1:
class Solution { public: int findUnsortedSubarray(vector<int>& nums) { int start = nums.size()-1,end = 0; vector<int> sort_nums(nums); sort(sort_nums.begin(),sort_nums.end()); for(int i=0;i<nums.size();i++){ if(sort_nums[i] != nums[i]){ start = min(start,i); end = max(end,i); } } return (end-start>0)?end-start+1:0; } };
时间复杂度: O(nlogn) (排序需要nlogn)
空间复杂度:O(n)
思想2:
这个算法背后的思想是无序子数组中最小元素的正确位置可以决定左边界,最大元素的正确位置可以决定右边界。
因此,首先我们需要找到原数组在哪个位置开始不是升序的。我们从头开始遍历数组,一旦遇到降序的元素,我们记录最小元素为 minmin 。
类似的,我们逆序扫描数组 numsnums,当数组出现升序的时候,我们记录最大元素为 maxmax。
然后,我们再次遍历 numsnums 数组并通过与其他元素进行比较,来找到 minmin 和 maxmax 在原数组中的正确位置。我们只需要从头开始找到第一个大于 minmin 的元素,从尾开始找到第一个小于 maxmax 的元素,它们之间就是最短无序子数组。
我们可以再次使用下图作为说明:
代码2:
class Solution { public: int findUnsortedSubarray(vector<int>& nums) { bool flag = false; int min_num=INT_MAX,max_num=INT_MIN; for(int i=0;i<nums.size()-1;i++){ if(nums[i]>nums[i+1]) flag = true; if(flag) min_num = min(min_num,nums[i+1]); } flag= false; for(int i=nums.size()-2;i>=0;i--){ if(nums[i]>nums[i+1]) flag = true; if(flag) max_num = max(max_num,nums[i]); } int l,r; for(l=0;l<nums.size();l++) if(nums[l]>min_num) break; for(r=nums.size()-1;r>=0;r--) if(nums[r]<max_num) break; return (r-l<0)?0:r-l+1; //注意这个判断条件,与上面两个循环有关 } };