给你一个下标从 0 开始的 正 整数数组 nums
。
如果 nums
的一个子数组满足:移除这个子数组后剩余元素 严格递增 ,那么我们称这个子数组为 移除递增 子数组。比方说,[5, 3, 4, 6, 7]
中的 [3, 4]
是一个移除递增子数组,因为移除该子数组后,[5, 3, 4, 6, 7]
变为 [5, 6, 7]
,是严格递增的。
请你返回 nums
中 移除递增 子数组的总数目。
注意 ,剩余元素为空的数组也视为是递增的。
子数组 指的是一个数组中一段连续的元素序列。
示例 1:
输入:nums = [1,2,3,4] 输出:10 解释:10 个移除递增子数组分别为:[1], [2], [3], [4], [1,2], [2,3], [3,4], [1,2,3], [2,3,4] 和 [1,2,3,4]。移除任意一个子数组后,剩余元素都是递增的。注意,空数组不是移除递增子数组。
示例 2:
输入:nums = [6,5,7,8] 输出:7 解释:7 个移除递增子数组分别为:[5], [6], [5,7], [6,5], [5,7,8], [6,5,7] 和 [6,5,7,8] 。 nums 中只有这 7 个移除递增子数组。
示例 3:
输入:nums = [8,7,6,6] 输出:3 解释:3 个移除递增子数组分别为:[8,7,6], [7,6,6] 和 [8,7,6,6] 。注意 [8,7] 不是移除递增子数组因为移除 [8,7] 后 nums 变为 [6,6] ,它不是严格递增的。
提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
提示 1
Calculate the largest x
such that nums[0..x]
is strictly increasing.
提示 2
Calculate the smallest y
such that nums[y..nums.length-1]
is strictly increasing.
提示 3
For each i
in [0, x]
, select the smallest j
in [y, nums.length - 1]
. Then we can keep the prefix with any suffix of [j, nums.length - 1]
(including the empty one).
提示 4
Note that when i
increases, j
won’t decrease. Use two-pointers.
提示 5
Note that we cannot delete an empty array, but we can delete the whole array.
解法: 双指针+不定长滑动窗口
class Solution {
public long incremovableSubarrayCount(int[] nums) {
int n = nums.length;
int x = 0;
while (x <= n - 2 && nums[x] < nums[x + 1]) {
x++;
}
// 数组nums[0..n - 1] 严格单调递增
if (x == n - 1) {
return (long)(1 + n) * n / 2;
}
// nums[0..x] 严格单调递增
// 可以移除 nums[x + 1..n - 1]...nums[0..n - 1] 共 x + 2 个
long ans = x + 2;
for (int y = n - 1; y == n - 1 || nums[y] < nums[y + 1]; y--) {
while (x >= 0 && nums[x] >= nums[y]) {
x--;
}
// nums[0..x]nums[y..n - 1] 严格单调递增
// 可以移除 nums[x + 1..y - 1]...nums[0..y - 1] 共 x + 2 个
ans += x + 2;
}
return ans;
}
}
复杂度分析
- 时间复杂度:O(n),n 是 数组 nums 的长度。注意二重循环中的 i 只会减小不会增大,i 只会减小 O(n) 次,所以二重循环的次数也是 O(n)的。
- 空间复杂度:O(1)。