fucking-algorithm
fucking-algorithm copied to clipboard
小而美的算法技巧:差分数组 :: labuladong的算法小抄
- 又是学废(bushi)了的一天
倒霉了,一遍没看懂/(ㄒoㄒ)/~~
0 <= trips[i][1] < trips[i][2] <= 1000 不应该是最多 1001 个车站么?
@lumaster 感谢指出,文中写错了,我改下
倒霉了,一遍没看懂/(ㄒoㄒ)/~~
多看几遍 上手敲一敲 (自己敲) 理解逻辑 加油!
好啊,还能刷到收费的题目,赚了赚了,我说我在lc插件和力扣翻了一会儿没看到这题
佩服这些设计者的脑子,我可能一辈子都想不到这么秒的方法。
这里的原数组 nums
对应的就是前缀和数组 prefixSum
,差分数组 diff
对应的就是前缀和中的原数组 nums
。
因此对于假前缀和数组第 [i,j]
位的加减操作,就可以理解为对原数组第 i
位加减某个数,第 j+1
位进行相反操作,就可以使前缀和数组表现为第 [i, j]
位同时加减某个数
打卡1
如果trips = [[9,0,1]], capacity = 4 这情况应该是false. 因为一开始就不能进9个人. 所以应该多加一个检查 if (val > capacity) { return false; }
@jay-zhu 可以,但也不是必须的,最后那个 for 循环会统一检查。
有点懵
看到最多1001的时候震惊了,我竟然用双循环找最大值
区间[i,j]
增加 val
但是差分数组 一起增大的 差分数组中间不变(a + val - b-val) == a-b
只是差分数组的第一个和最后一个 这两个元素不同
i
位置元素 diff[i] = diff[i] + val
j
位置后面元素 diff[j+1] = diff[i+1] - val
这里是不是应该注释一下,nums[i] 表示 站点 i 到站点 i+1 之间的乘客人数。由此,虽然有1001个站点,但是 nums 的长度只要 1000 就可以了。
“分别适用不同的常见”,应该是“分别适用不同的场景”。
打卡,感谢!
@bert82503 感谢指出,已修复~
利用东哥的差分数组,解决力扣:1094. 拼车,原理一样,代码简单优化了下:
class Solution {
public boolean carPooling(int[][] trips, int capacity) {
int[] diff=new int[1000+1];
int maxLen=1;
for(int[] trip:trips){
int i=trip[1],j=trip[2],val=trip[0];
maxLen=Math.max(maxLen,j);//maxLen记录最大的公里数
updateDiff(diff,i,j,val);
}
return convertDiff(diff,maxLen,capacity);
}
//更新差分数组,公里数为[i,j-1]的增加val
public void updateDiff(int[] diff,int i,int j,int val){
diff[i]+=val;
diff[j]-=val;
}
public boolean convertDiff(int[] diff,int maxLen,int capacity){
if(diff[0]>capacity) return false;
for(int i=1;i<=maxLen;i++){
diff[i]=diff[i-1]+diff[i];
//判断是否超载
if(diff[i]>capacity) return false;
}
return true;
}
}
区间加法:
class Solution {
vector<int> diff;
public:
vector<int> getModifiedArray(int length, vector<vector<int>>& updates) {
vector<int> A;//初始数组
A.resize(length);
diff=differ(A);
for(int i=0;i<updates.size();i++){
int start=updates[i][0];
int end=updates[i][1];
int val=updates[i][2];
diff=increment(start,end,val);
}
return result();
}
//update{start,end,inc}
vector<int> differ(vector<int>& A){//构造差分数组
int n=A.size();
diff.resize(n);
diff[0]=A[0];
for(int i=1;i<diff.size();i++){
diff[i]=A[i]-A[i-1];
}
return diff;
}
vector<int> increment(int start,int end,int val){//
diff[start]+=val;
if(end+1<diff.size()){//此处为end+1
diff[end+1]-=val;
}
return diff;
}
vector<int> result(){
vector<int> res;
res.resize(diff.size());
res[0]=diff[0];
for(int i=1;i<res.size();i++){
res[i]=res[i-1]+diff[i];
}
return res;
}
};
python实现打卡🥰
class Diff:
def __init__(self,nums) -> None:
self.diff = [nums[0]]
for i in range(1, len(nums)):
self.diff.append(nums[i]-nums[i-1])
pass
def increment(self, i, j, val):
self.diff[i] +=val
if j+1 < len(self.diff):
self.diff[j+1] -=val
def cal(self, cap):
res = 0
for i in range(len(self.diff)):
res += self.diff[i]
if res > cap:
return False
return True
class Solution:
def carPooling(self, trips: List[List[int]], capacity: int) -> bool:
df = Diff([0]*1001)
for i in trips:
df.increment(i[1],i[2]-1,i[0])
return df.cal(capacity)
优化了一下 拼车
class Solution {
public:
bool carPooling(vector<vector<int>>& trips, int capacity) {
// 0 <= fromi < toi <= 1000 最多有一千零1个车站
vector<int> res(1001, 0);
for(auto trip : trips){
res[trip[1]] += trip[0];
if(trip[2] < res.size()){
res[trip[2]] -= trip[0];
}
}
for(int i = 1; i < res.size(); i++){
res[i] += res[i-1];
}
for(auto r : res){
if(r > capacity){
return false;
}
}
return true;
}
};
感觉diff[i] 不一定要nums[i] - nums[i-1],,diff[i] = nums[i] + nums[i-1]其实也可以
滴滴滴打卡
太爱这个模版了
上车下车,就是区间里的数字加上人数!
看完之后so easy!
原理简单,难的是具体问题怎么转化成差分😒😒