1574. 删除最短的子数组使剩余数组有序
方法:双指针 + 找规律
解题思路
去除子数组的可能情况:
-
将第一个递减序列的左端点到末尾的子数组去掉;
-
将最后一个递减序列的右端点到起点的子数组去掉;
-
左端点:起点 和 第一个递减序列的左端点之间取,
右端点:最后一个递减序列的右端点和末尾之间取,
使得\([l, r]\)最小,且去除后符合条件。
代码
static const auto io_sync_off = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
return nullptr;
}();
class Solution {
public:
int findLengthOfShortestSubarray(vector<int>& arr) {
int n = arr.size();
int startLeft = 0, endRight = n - 1; // 分别表示第一个递减序列的左端点 和 最后一个递减序列的右端点
while (startLeft < n - 1 && arr[startLeft] <= arr[startLeft + 1]) startLeft ++ ;
if (startLeft == n - 1) return 0; // 此时数组自身非递减
while (endRight && arr[endRight - 1] <= arr[endRight]) endRight -- ;
if (arr[endRight] >= arr[startLeft]) return endRight - startLeft - 1; // 判断最短情况是否成立
int ans = min(n - startLeft - 1, endRight); // 取1和2中的最小值
for (int l = 0, r = endRight; r < n && l <= startLeft; ) { // 取ans和3中的最小值
// 找第一个大于等于arr[l]的下标,保证r距离l最近
r = lower_bound(arr.begin() + r, arr.end(), arr[l]) - arr.begin();
if (r < n) {
// 找第一个大于arr[r]的下标,保证l距离r最近
l = upper_bound(arr.begin() + l, arr.begin() + startLeft + 1, arr[r]) - arr.begin();
ans = min(ans, r - l);
}
}
return ans == n ? ans - 1 : ans;
}
};
复杂度分析
时间复杂度:\(O(n)\);
空间复杂度:\(O(1)\)。

浙公网安备 33010602011771号