数组算法——差分数组
Problem: 1094. 拼车
思路1:双for遍历
首先想到的是直接在原数组上操作。
public boolean carPooling(int[][] trips, int capacity) {
//声明一个res数组,用于记录每一个站时车上的乘客数量
int[] res = new int[1001];
//遍历trips,取出每一次trip
for (int i = 0; i < trips.length; i++) {
//第i趟trip的乘客数量
int val=trips[i][0];
//第i趟trip val个乘客的上车站
int start = trips[i][1];
//第i趟trip val个乘客的下车站
int end=trips[i][2];
//遍历res,将res[start,end-1]区间的元素+=val,
//tips:由于end处乘客已经下车,此时可以上车,所以闭区间应该是[i,j-1]
for (int j = start; j < end; j++) {
res[j]+=val;
}
}
//检查旅行中是否超载
for (int i = 0; i < res.length; i++) {
if (res[i]>capacity) {
return false;
}
}
return true;
}
时间复杂度为O(n2)
空间复杂度为O(1)(这里没有考虑res)
思路2:差分数组
对于思路一,每一次旅行时都需要对res[i,j]循环加减(o(n2))
而我们可以选择用构造一个更适合该问题的数组为代价(牺牲int[]空间),
不再需要循环加减即可完成res的统计
我们需要构造一个diff数组,这个数组记录的是原num[i]nums[i-1]的差
即diff[i]=nums[i]-nums[i-1]
如下图所示
Q:为什么要构造这个数组呢?
A:因为diff数组记录了nums相邻元素的关系,对于差分数组diff,闭区间元素的整体的±是有下面的规律的
diff[i]+=val;diff[j+1]-=val;
这个等同于
for (int j = start; j < end; j++) {
res[j]+=val;
}
而本题需要的是从[i,j]同时+或-来统计从i站到j站 车上的乘客人数。
时间复杂度为O(n)
空间复杂度为O(n)
public class DifferenceArray {
//差分数组
private int[] diff;
//根据nums构造diff
public DifferenceArray(int[] nums) {
assert nums==null||nums.length>0;
diff=new int[nums.length];
diff[0]=nums[0];
for (int i = 1; i < nums.length; i++) {
diff[i]=nums[i]-nums[i-1];
}
}
//根据diff来对[i,j]闭区间的nums元素+或-
public void increment(int i,int j,int val){
//根据差分数组的性质
//只需diff[i]+=val,diff[j+1]-=val;
diff[i]+=val;
if(j+1<diff.length){
diff[j+1]-=val;
}
}
//根据diff返回原来的nums数组
public int[] returnResultArray(){
int[] res = new int[diff.length];
res[0]=diff[0];
for (int i = 1; i < diff.length; i++) {
res[i]=res[i-1]+diff[i];
}
return res;
}
}
public boolean carPooling(int[][] trips, int capacity) {
int[] nums = new int[1001];
DifferenceArray dfa = new DifferenceArray(nums);
for(int[] trip:trips){
//该trip的乘客数量
int val = trip[0];
//乘客在trip[i]上车
int i=trip[1];
//乘客在trip[2]已经下车
//所以闭区间是trip[2]-1
int j=trip[2]-1;
//对dfa的diff[i,j]进行+运算
dfa.increment(i,j,val);
}
int[] res = dfa.returnResultArray();
//检查res[i]是否大于capacity
//若大于,则说明false
for (int i = 0; i < res.length; i++) {
if (capacity < res[i]) {
return false;
}
}
return true;
}