题目链接:https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/
题意:
给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的 最短 子数组,并输出它的长度。
方法:左右坐标往中间夹,找到最短长度,由于进行了排序时间复杂度为O(nlogn) ,并且使用了一个向量存储向量,空间复杂度为O(nlogn)
class Solution {
public:
int findUnsortedSubarray(vector<int>& nums) {
vector<int> vct(nums);//存储一个等长的数组
sort(vct.begin(),vct.end());//升序排序
int len = nums.size();//记录数组长度
int left=0,right=len-1;//左侧坐标,右侧坐标
while(left<len)
{
if(vct[left]!=nums[left])//从左到右,如果出现第一个在数组中不相等的元素就退出循环
{
break;
}
left++;//从左到右
}
if(left==len) return 0;
while(right>=0)
{
if(vct[right]!=nums[right])//从右到左,如果出现第一个在数组中不相等的元素就退出循环
{
break;
}
right--;//从右到左
}
return right-left+1;
}
};
方法二:使用两次扫描,找到最左侧比最短子数组中最小的元素大的元素,找到最右侧比最短子数组中最大的元素小的元素,利用这两个元素的位置,找到缝隙的数目,在它们缝隙的数目的基础上加上1,就是最短长度。使用了两边扫描套用了两次一重循环,时间复杂度O(n),空间复杂度O(1)
class Solution {
public:
int findUnsortedSubarray(vector<int>& nums) {
int len = nums.size();//元素个数
int right = 0,left = len;//右侧坐标从0开始扫描,左侧坐标从len开始扫描
int minx = nums[len-1],maxx = nums[0];//存储扫描过的最小值,存储扫描过的最大值
for(int i=len-1;i>=0;i--)//从右往左扫描,找的是出现的需要排序的数字的位置
{
if(nums[i]>minx)//如果对应的值比扫描过的最小的大,说明这个位置的值是需要排序的
left = i;
minx = min(minx,nums[i]);//保存扫描过的最小值,并存储
}
for(int i=0;i<len;i++)
{
if(nums[i]<maxx)//如果对应的值比扫描过的最大的大,说明这个位置的值是需要排序的
right = i;
maxx = max(maxx,nums[i]);//保存扫描过的最大值,并存储
}
return max(right-left+1,0);//如果不存在,right-left自然会小于0,之所以加1是因为项的个数一般都会比空隙大1
}
};