LeetCode HOT100 - 最短无序连续子数组
考虑应该是什么样的
如果我们有已经排完序的数组
那么和排完序数组前缀和后缀相同的不需要修改,其他的是需要进行排序的部分
O(n) 情况下,我们可以先去找哪些是必须要被排序的
因为只能排序一次,所以数组中的逆序对是一定要被操作的,所以我们维护这些的最小值和最大值
这样我们相当于得到了一个要操作的区间
但是这个区间可能还不是完整的区间
因为比如当前数组的前缀虽然是有序的,但是和实际排完序的数组并不是重叠的
所以从数组的前缀和后缀再做一次遍历
前缀:如果当前元素大于要操作区间中的最小值,因为排序完是有序的,所以它也应该在排序区间中
后缀:如果当前元素小于要操作区间中的最大值,同理
class Solution {
public:
int findUnsortedSubarray(vector<int>& a) {
int n = a.size();
int ansl = n + 5, ansr = -1;
for (int i = 1; i < n; i++) {
if (a[i] < a[i - 1]) {
ansl = min(ansl, i - 1);
ansr = max(ansr, i);
}
cout << ansl << ' ' << ansr << '\n';
}
if (ansl == n + 5) {
return 0;
}
int mn = *min_element(a.begin() + ansl, a.begin() + ansr + 1);
int mx = *max_element(a.begin() + ansl, a.begin() + ansr + 1);
cout << mn << ' ' << mx << '\n';
for (int i = 0; i < ansl; i++) {
if (a[i] > mn) {
ansl = min(ansl, i);
break;
}
}
cout << ansl << ' ' << ansr << '\n';
for (int i = n - 1; i > ansr; i--) {
if (a[i] < mx) {
ansr = max(ansr, i);
break;
}
}
cout << ansl << ' ' << ansr << '\n';
return ansr - ansl + 1;
}
};
不过这样运行的有些慢
参考这篇题解
排完序后,实际上就是最大值会在最后一位,最小值会在第一位
所以从前往后扫,维护当前的最大值,小于这个最大值的是一定要被排序的(包含了我们前面逆序对的思路),同理,从后往前扫,大于最小值的也是要被排序的
这样运行的次数可以减少
class Solution {
public:
int findUnsortedSubarray(vector<int>& a) {
int n = a.size();
int mx = a[0];
int ansr = -1;
for (int i = 1; i < n; i++) {
if (a[i] < mx) {
ansr = i;
} else {
mx = a[i];
}
}
int mn = a.back();
int ansl = 0;
for (int i = n - 2; i >= 0; i--) {
if (a[i] > mn) {
ansl = i;
} else {
mn = a[i];
}
}
return ansr - ansl + 1;
}
};

浙公网安备 33010602011771号