数组算法——差分数组

本文介绍了使用差分数组算法解决拼车问题,通过构造diff数组减少计算量,将双for遍历的时间复杂度从O(n^2)降低到O(n),空间复杂度也相应提升。
摘要由CSDN通过智能技术生成

数组算法——差分数组

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]

如下图所示

image.png

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;
    }
  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程就是n踢r

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值