差分法。
差分法就是不记录当前具体的值,而是记录值的变化量。出生/死亡人数、上/下公交车,都是这类题目。
class Solution {
public int maximumPopulation(int[][] logs) {
// 差分法:arr记录人口变化量
int[] arr = new int[101];
for (int[] log : logs) {
arr[log[0] - 1950]++;
arr[log[1] - 1950]--;
}
int max = 0;
int num = 0;
int res = 0;
for (int i = 0; i < 101; i++) {
num += arr[i];
if (num > max) {
max = num;
res = i + 1950;
}
}
return res;
}
}
滑动窗口,以及贪吃蛇优化
```java
class Solution_1855 {
public int maxDistance(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int L = 0;
int R = 0;
while (L < len1 && R < len2) {
if (nums1[L] > nums2[R]) {
L++;
}
R++;
}
// 因为本题中的窗口大小可以是0(一般的滑窗大小至少也是1的),所以特判一下
return R - L - 1 >= 0 ? R - L - 1 : 0;
}
}
2 * (3 + 2 + 5)这个式子中,有两个可变量,"子数组最小值"和"子数组的和",按照一般的思路只能是暴力子数组的范围(i, j)。
我们不妨先固定一个变量::最小值。
在遍历的时候,遍历到数字作为最小值固定,那么它所在的子数组显然越大越好(和就越大);我们通过使用两次单调栈,就能找出子数组的左右边界。
class Solution {
public int maxSumMinProduct(int[] nums) {
int len = nums.length;
// 求前缀和
long[] preSum = new long[len + 1];
for (int i = 0; i < len; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
// 左右边界
int[] leftBound = new int[len];
int[] rightBound = new int[len];
Arrays.fill(leftBound, 0);
Arrays.fill(rightBound, len - 1);
// 两次单调栈,找出右、左边界(右、左侧第一个小于它的数的位置)
ArrayDeque<Integer> stack1 = new ArrayDeque<>();
for (int i = 0; i < len; i++) {
while (!stack1.isEmpty() && nums[i] < nums[stack1.peek()]) {
rightBound[stack1.pop()] = i - 1;
}
stack1.push(i);
}
ArrayDeque<Integer> stack2 = new ArrayDeque<>();
for (int i = len - 1; i >= 0; i--) {
while (!stack2.isEmpty() && nums[i] < nums[stack2.peek()]) {
leftBound[stack2.pop()] = i + 1;
}
stack2.push(i);
}
// 遍历到的数字固定为最小值
long res = 0L;
for (int i = 0; i < len; i++) {
int L = leftBound[i];
int R = rightBound[i];
res = Math.max(res, (preSum[R + 1] - preSum[L]) * nums[i]);
}
return (int) (res % (1000000007));
}
}
检索标记:
5750. 人口最多的年份给你一个二维整数数组 logs ,其中每个 logs[i] = [birthi, deathi] 表示第 i 个人的出生和死亡年份。年份 x 的 人口 定义为这一年期间活着的人的数目。第 i 个人被计入年份 x 的人口需要满足:x 在闭区间 [birthi, deathi - 1] 内。注意,人不应当计入他们死亡当年的人口中。返回 人口最多 且 最早 的年份。1855. 下标对中的最大距离给你两个 非递增 的整数数组 nums1 和 nums2 ,数组下标均 从 0 开始 计数。下标对 (i, j) 中 0 <= i < nums1.length 且 0 <= j < nums2.length 。如果该下标对同时满足 i <= j 且 nums1[i] <= nums2[j] ,则称之为 有效 下标对,该下标对的 距离 为 j - i 。返回所有 有效 下标对 (i, j) 中的 最大距离 。如果不存在有效下标对,返回 0 。一个数组 arr ,如果每个 1 <= i < arr.length 均有 arr[i-1] >= arr[i] 成立,那么该数组是一个 非递增 数组。1856. 子数组最小乘积的最大值一个数组的 最小乘积 定义为这个数组中 最小值 乘以 数组的 和 。比方说,数组 [3,2,5] (最小值是 2)的最小乘积为 2 * (3+2+5) = 2 * 10 = 20 。
给你一个正整数数组 nums ,请你返回 nums 任意 非空子数组 的最小乘积 的 最大值 。由于答案可能很大,请你返回答案对 109 + 7 取余 的结果。请注意,最小乘积的最大值考虑的是取余操作 之前 的结果。题目保证最小乘积的最大值在 不取余 的情况下可以用 64 位有符号整数 保存。子数组 定义为一个数组的 连续 部分。