之前我有一篇 《差分+前缀和》的学习笔记,记录了差分的思想和基本用法。这里就只记录灵神题单的刷题记录。
我记得这是哪次每日一题来着,入门差分前缀和了。
差分数组维护每站新增的乘客(当然数量可以是≤0的),每一项在上车对应位置加。下车对应位置减即可。
class Solution {
public boolean carPooling(int[][] trips, int capacity) {
int[] diff = new int[1001];
for (int[] trip : trips) {
diff[trip[1]] += trip[0];
diff[trip[2]] -= trip[0];
}
for (int i : diff) {
capacity -= i;
if(capacity<0){
return false;
}
}
return true;
}
}
同样入门题。差分数组维护每站新增座位。对于每个预订项,first(i)增加对应量,而last(i)之后就不再预订这些位置,所以要减掉。
class Solution {
public int[] corpFlightBookings(int[][] bookings, int n) {
int[] ans = new int[n];
// 我有一计O(n)的差分前缀和,可做此题
for (int[] booking : bookings) {
ans[booking[0]-1] += booking[2];
if(booking[1]
也是入门题。差分数组维护每个位置的移位偏移量,前缀和还原。
修改字符的时候,可以利用向左移动1等于向右移动25的技巧来规避掉对于负数的分类讨论。
import java.util.Arrays;
class Solution {
public String shiftingLetters(String s, int[][] shifts) {
int[] diff = new int[s.length()];
int dir ;
for (int[] shift : shifts) {
dir = shift[2]==1?1:-1;
diff[shift[0]] += dir;
if(shift[1]
class Solution {
public String shiftingLetters(String s, int[][] shifts) {
char[] chars = s.toCharArray();
int n = chars.length;
int[] diff = new int[n + 1];
for(int[] shift : shifts){
int dir = shift[2] == 1 ? 1 : 25;
diff[shift[0]] += dir;
diff[shift[1] + 1] -= dir;
}
int t = 0;
for(int i = 0; i < n; i++){
t += diff[i];
chars[i] = (char)('a' + (chars[i] + t - 'a') % 26);
}
return new String(chars);
}
}
说实话,这题是标了个差分,提示我了。不标差分我真想不明白,汗流浃背了捏。
差分数组维护每个区间端点的使用次数,前缀和还原后就是每个数字用到的次数。最终的结果就是这些次数中的最大值。
想想看为什么,如果任意某个数字在不同区间出现了多次,那么我们就要把这些区间全部拆开来,分到不同的组里,取这个次数的最大值,一定能容纳其他较小值的出现次数对应的所有区间。(反正这是直观上很显然的事情,我就不严谨证明了)
class Solution {
static int len = (int)1e6+1;
public int minGroups(int[][] intervals) {
int[] diff = new int[len + 1];
for (int[] interval : intervals) {
diff[interval[0]]++;
diff[interval[1]+1]--;
}
int ans = 1;
// 原地更新
for (int i = 1; i < diff.length; i++) {
diff[i] += diff[i-1];
ans = Math.max(diff[i],ans);
}
return ans;
}
}
这题我感觉自己思路很混(或者说很玄学),不知道严谨不严谨。
这道题是只能对某一个区间中的每一个元素去进行-1操作的,因此是不可逆的,一旦一个元素减少了,那他就再也没法加回来了。
对于第一个元素,也就是0号索引的。如果最终返回true,那么它一定变成0。而包含了这第一个元素的子数组有且只有一个,也就是索引区间[ 0, k-1],那么我们就只能对这个区间进行nums[0]次-1操作。最终使nums[0]变为0。
这样我们就可以把nums[0]元素撇开完全不看了,因为之前说过,这个元素的变化是不可逆的,它没有机会再加上去,然后再减回0,因此一旦它变成0,就再也不能动了,所以我们可以把它撇开完全不管了。
这样整个数组就变成了[1,n-1]了,对于nums[1],同样的,因为nums[0]不在了,所以有且仅有索引区间[1,k]能够执行-1操作,使得nums[1]变成0。这个过程和之前是一模一样的。
因此我们要做的就是,从左往右遍历,把当前位置变成0的同时,也连带把它后面k-1个元素执行同样次数的-1操作。比如现在遍历到3,那么后面的k-1个元素全部-3。
这就可以用一个差分数组来记录。差分数组维护每个元素的增减量,通过前缀和还原,这个在代码实现上是可以原地计算的。
那么什么时候判断失败,简单想想,很显然有且仅有两种:
class Solution {
public boolean checkArray(int[] nums, int k) {
int n = nums.length;
int[] diff = new int[n];
diff[0] = nums[0];
if(knums[i]||tmpn-k){
return false;
}
int dis = nums[i]-tmp;
if(dis!=0){
tmp+=dis;
if(i+k
这题有combo的,就是上面的第五题(乐
首先看到最大化最小值,很显然二分板子。
初始我们要预计算每个电站的初始电量,不然不知道差每次二分的mid多少。这个很显然也是差分前缀和板子,和前面第一第二题很像,就是一个区间增量的板子。同时还可以在前缀和还原时维护上述所说的最小电量。
import java.util.ArrayList;
import java.util.List;
class Solution {
static long min;
public long maxPower(int[] stations, int r, int k) {
min = Long.MAX_VALUE;
long[] iP= calPower(stations, r);
long lp,rp,mid,ans;
lp = min;
rp = min+k+1;
ans = lp;
while(lp