题目
滑动窗口
public class Main {
public static void main(String[] args) {
Main main = new Main();
int [] nums = new int[] {1,0,1,2,1,1,7,5};
int [] nums2 = new int[] {0,1,0,1,0,1,0,1};
main.maxSatisfied(nums, nums2, 3);
}
public int maxSatisfied(int[] customers, int[] grumpy, int X) {
int sum = Arrays.stream(customers).sum();
if (X == customers.length) {
return sum;
}
// dp[i]记录customers i位置之后, 所有元素的和
int [] dp = new int[customers.length];
dp[0] = sum;
for(int i = 1; i < customers.length; i ++) {
dp[i] = dp[i - 1] - customers[i - 1];
}
// dp2[i] 记录了考虑grumpy后每个位置的和
int [] dp2 = new int[customers.length];
int sumPart = 0;
for (int i = 0; i < customers.length; i ++) {
if (grumpy[i] == 0) {
sumPart = sumPart + customers[i];
}
}
dp2[0] = sumPart;
for(int i = 1; i < customers.length; i ++) {
if (grumpy[i - 1] == 0) {
dp2[i] = dp2[i - 1] - customers[i - 1];
} else {
dp2[i] = dp2[i - 1];
}
}
// 遍历customers, 以X为窗口, 计算窗口笼罩时, 客流量的最大值
int left = 0;
int right = left + X;
int max = Integer.MIN_VALUE;
while(right <= customers.length) {
int tempSum = 0;
if (left > 0) {
// 窗口左边
tempSum = tempSum + dp2[0] - dp2[left];
}
// 窗口中间
if (right == customers.length) {
tempSum = tempSum + dp[left];
} else {
tempSum = tempSum + dp[left] - dp[right];
}
// 窗口右侧
if (right < customers.length) {
tempSum = tempSum + dp2[right];
}
max = Math.max(tempSum, max);
left ++;
right = left + X;
}
return max;
}
}
基本思路
-
利用一个长度为X的窗口, 计算窗口左边的累加和, 计算窗口的累加和, 计算窗口右边的累加和, 三部分的和就是题目的答案, 取最大值
-
提前计算好每个位置到最后的和, 每次计算时查询即可, 无需循环
滑动窗口2
public class Main {
public static void main(String[] args) {
Main main = new Main();
int [] nums = new int[] {4, 10, 10};
int [] nums2 = new int[] {1, 1, 0};
main.maxSatisfied(nums, nums2, 2);
}
public int maxSatisfied(int[] customers, int[] grumpy, int X) {
if (customers.length == X) {
return Arrays.stream(customers).sum();
}
// 先计算出确定满意的顾客量
// 再利用X作为滑动窗口, 计算出额外增加的顾客量, 记录窗口内额外增加顾客的最大值
int sum1 = 0;
for (int i = 0; i < customers.length; i ++) {
if (grumpy[i] == 0) {
sum1 = sum1 + customers[i];
}
}
int left = 0;
int right = left + X - 1;
int sum2 = 0;
int max = 0;
while (right < customers.length) {
if (left == 0) {
// 第一次窗口内的额外增加值需要循环
for (int j = 0; j < X; j ++) {
if (grumpy[j] == 1) {
sum2 = sum2 + customers[j];
}
}
} else {
// 移入新增加的元素
if (grumpy[right] == 1) {
sum2 = sum2 + customers[right];
}
}
max = Math.max(max, sum2);
// 移出当前left的元素
if (grumpy[left] == 1) {
sum2 = sum2 - customers[left];
}
left ++;
right = left + X - 1;
}
return sum1 + max;
}
}
基本思路
-
既然利用滑动窗口, 就应该使用移入和移出的元素对于窗口的影响来做, 而不是像上面一样考虑数组两端
-
总人数可以拆分为 已经确定的客流和窗口X代表的增加客流