链接:https://leetcode.cn/problems/count-the-number-of-incremovable-subarrays-ii/description/
看视频加自己理解的,写一下思考过程
注意:子数组是连续的序列
所以保留下来的序列只能是单边的,不能是中间的
不能移除空数组,所以j>=i+2
第一步:选出最长的前缀递增子序列,设最后的那个数字的下标为i
第二步:ans+=i+2,认为是当要删的子序列是为整个数组的最后一个数时,可以有多少种删除方法
例如,对1 4 3 2 4 5 3 6这个数组,i指向1,即元素4,
当要删除的子序列的右端点固定为最后一个数字时,可以删除:
1)从i+1这个位置开始到最后一个数字(记为j)
2)从i开始到j
3)从i-1开始到j
4)...
5)重复上述过程,一直到i=0,一共有i+2个子序列可以删除
第三步:开始枚举,从最后一个元素开始,记为j,假设要删除的子序列的最后一个数字的下标是j-1,计算此时可以有多少种删除方法。因为子数组是连续的序列,所以j到n-1这一段也同样必须是递增的,在循环的时候要加上这个判断条件
1)如果下标j的数比下标i大,那么可以删除:
a.i+1到j-1
b.i到j-1
c.i-1到j-1
d....
e.0到j-1
一共i+2个子序列
此时ans+=i+2
2)如果下标j的数比下标i小或等于,将i向左移,直到nums[i]<nums[j],随后和第一种情况类似,ans+=i+2
这里本来我想取一个i_copy等于i的,后来发现不需要,因为j后面的那一段是递增的,如果当前这个j比i小,那么再往前走的时候必然也不存在一个j比当前的i大
此时要注意,向左移的过程,i不能小于等于0,如果出现这种情况,说明当前这个nums[j]比递增序列的所有值都小,那么就只能ans+=1,认为是计算删除掉了0到j-1这一段。
看过灵神的代码后,发现不需要执行ans+=1这种情况,因为如果i小于等于0了,那么此时i==-1,且不会再变化了,还是执行ans+=i+2是一样的+1,可以简化代码
出现了i==-1的情况后,说明已经不可能再找到一个中间的数组,删除这个数组后保留的元素是递增的,此时就只需要对j进行遍历,每次遍历就ans+=1
AC代码:
class Solution {
public:
long long incremovableSubarrayCount(vector<int>& nums) {
long long n=nums.size();
long long i=0;
while(i<n-1&&nums[i]<nums[i+1])
i+=1;
if(i==n-1)
return n+(n*n-n)/2;
long long ans = i+2;
long long j=n-1;
for(j;j==n-1||nums[j]<nums[j+1];j--){
if(i>=0&&nums[j]>nums[i])
ans+=i+2;
else{
while(i>=0&&nums[i]>=nums[j])
i-=1;
ans+=i+2;
}
}
return ans;
}
};