以下代码来自 ,灵山茶
class Solution {
public long countSubarrays(int[] nums, int minK, int maxK) {
var ans = 0L;
// i0标记越界的值
int n = nums.length, minI = -1, maxI = -1, i0 = -1;
for (var i = 0; i < n; ++i) {
var x = nums[i];
if (x == minK) minI = i; // 最小值的索引小标一直在更新
if (x == maxK) maxI = i; // 最大值的索引下标一直在更新
if (x < minK || x > maxK) i0 = i; // 子数组不能包含 nums[i0],他也作为其中一个边界
// 下面这个式子表示,上方不断更新最小值下标和最大值下标,只取最小,作为左边界
// 只有当两个都更新的时候,才会选择其中更小的一个作为新的边界开始。
ans += Math.max(Math.min(minI, maxI) - i0, 0);
}
return ans;
}
}
作者:endlesscheng
链接:https://leetcode.cn/problems/count-subarrays-with-fixed-bounds/solution/jian-ji-xie-fa-pythonjavacgo-by-endlessc-gag2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解答代码:上面的代码有点难看懂,大概是做了这样一件事,i0标记越界数字下标,minI和maxI分别标记符合目标区间最小值下标和最大值下标。
上面ans += Math.max(Math.min(minI, maxI) - i0, 0);这段代码,完美剔除了未形成目标区域的情况。
遍历数字形成目标区域的三种情况如下:
第一种情况,后续的数字没有破坏目标区域(1最小,5最大),后面每增加一个数字,紫色区域 * 1。这个比较好理解,如果1,3,5前面有3个2,后面又出现4个2,总情况就是(3 + 1) * (4 + 1),20种情况。
第二种情况,if (x < minK || x > maxK) i0 = i; 越界数字(蓝色线)出现在了maxI的右边,目标区域被破坏。此时不能累加值。等待新的目标区域形成。
第三种情况,更新新的目标区域。因为之前的情况都已经计算过了,可以直接舍去之前形成的区域,开始计算新的目标区域。(注意如果越界数字没有更新,还是上一个目标区域的情况,计算的时候,是需要计算蓝色线到红色矩形右边界的情况)。
感悟:大佬写的代码真好,我一直想着怎么去重,到最后也没有做好,计算机代码的编写不能总按照如人脑的习惯来,像这种累加计算各种情况的,就应该像大佬的代码一样,每新增一个值计算一次,细分来计算,这样不容易出错,时间复杂度也比额外处理去重要小。