《LeetCode之每日一题》:113.最短无序连续子数组
Posted 是七喜呀!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《LeetCode之每日一题》:113.最短无序连续子数组相关的知识,希望对你有一定的参考价值。
题目链接: 最短无序连续子数组
有关题目
给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的 最短 子数组,并输出它的长度。
示例 1:
输入:nums = [2,6,4,8,10,9,15]
输出:5
解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。
示例 2:
输入:nums = [1,2,3,4]
输出:0
示例 3:
输入:nums = [1]
输出:0
提示:
1 <= nums.length <= 104
-10^5 <= nums[i] <= 10^5
进阶:你可以设计一个时间复杂度为 O(n) 的解决方案吗?
题解
法一:排序
代码一:
int Is_sorted(int* nums, int numsSize){
for (int i = 0; i < numsSize - 1; i++){
if (nums[i] > nums[i + 1])
return 0;
}
return 1;
}
int cmp(int* a, int* b){
return *a - *b;
}
int findUnsortedSubarray(int* nums, int numsSize){
if (Is_sorted(nums, numsSize)) //特判
return 0;
int arr[numsSize];
memcpy(arr, nums, numsSize * sizeof(int));
qsort(arr, numsSize, sizeof(int), cmp);
int l = 0, r = numsSize - 1;
while(nums[l] == arr[l]) l++;
while(nums[r] == arr[r]) r--;
return r - l + 1;
}
代码二:
int cmp(int* a, int* b){
return *a - *b;
}
int findUnsortedSubarray(int* nums, int numsSize){
int ans = 0, l = 0, r = numsSize - 1;
int arr[numsSize];
memcpy(arr, nums, numsSize * sizeof(int));
qsort(arr, numsSize, sizeof(int), cmp);
while(l < numsSize && arr[l] == nums[l]) l++;
while(r >= 0 && arr[r] == nums[r]) r--;
return l == numsSize ? 0 : r - l + 1 ;
}
法二:单调栈
int findUnsortedSubarray(int* nums, int numsSize){
int n = numsSize;
int stk[n], stkSize = 0;
int l = n - 1, r = 0;
for (int i = 0; i < n; i++){//寻找左边界
while(stkSize && nums[stk[stkSize - 1]] > nums[i]){
l = fmin(l, stk[stkSize - 1]);
stkSize--;
}
stk[stkSize++] = i;
}
stkSize = 0;//重置栈
for (int i = n - 1; i >= 0; i--){//寻找右边界
while(stkSize && nums[stk[stkSize - 1]] < nums[i]){
r = fmax(r, stk[stkSize - 1]);
stkSize--;
}
stk[stkSize++] = i;
}
return r - l > 0 ? r - l + 1 : 0;//示例[1]此时r 与 l 重合
}
时间复杂度:O(N)
空间复杂度:O(N)
法三:一次遍历
思想:
无序子数组中最小元素的正确位置可以决定左边界,最大元素的正确位置可以决定右边界
代码一:
int findUnsortedSubarray(int* nums, int numsSize) {
//if (is_sorted(nums.begin(), nums.end())){
// return 0;
// }
int n = numsSize;
int maxn = INT_MIN, right = -1;
int minn = INT_MAX, left = -1;
for (int i = 0; i < n; i++) {
//maxn与right从左往右寻找到 非排序与排序之间的过渡线
//找到比左边更大的数,我们更新maxn,
if (maxn > nums[i]) {
right = i;//[1,3,2,3,3],注意是发现大于nums[i]的数字更新下标
} else {
maxn = nums[i];//2 6
}
//minn与left从右往左寻找到 非排序与排序之间的过渡线
//找到比右边位置更小的数,我们更新minn,不然的更新下标
if (minn < nums[n - i - 1]) {
left = n - i - 1;//6
} else {
minn = nums[n - i - 1];//15 9
}
}
return right == -1 ? 0 : right - left + 1;
}
代码二:
int findUnsortedSubarray(int* nums, int numsSize){
int n = numsSize;
int i = 0, j = n - 1;
int minn = INT_MAX, maxn = INT_MIN;
//初始确定i j范围
while(i < n - 1 && nums[i] <= nums[i + 1]) i++;//等于的示例[1,3,2,3,3,3]
while(j > 1 && nums[j - 1] <= nums[j] ) j--;
if (i >= j) return 0;//示例[1]取等于
//找到无序数组中最大,最小值
for (int k = i; k <= j; k++){
minn = fmin(minn, nums[k]);
maxn = fmax(maxn, nums[k]);
}
//最终确定i j位置
while(i >= 0 && nums[i] > minn) i--;
while(j < n && nums[j] < maxn) j++;
return j - i - 1;
}
以上是关于《LeetCode之每日一题》:113.最短无序连续子数组的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 581. 最短无序连续子数组/611. 有效三角形的个数/15. 三数之和/18. 四数之和(双指针)