LeetCode1109之航班预订统计(相关话题:差分数组)

题目描述

这里有 n 个航班,它们分别从 1 到 n 进行编号。

有一份航班预订表 bookings ,表中第 i 条预订记录 bookings[i] = [firsti, lasti, seatsi] 意味着在从 firsti 到 lasti (包含 firsti 和 lasti )的 每个航班 上预订了 seatsi 个座位。

请你返回一个长度为 n 的数组 answer,其中 answer[i] 是航班 i 上预订的座位总数。

示例 1:

输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
输出:[10,55,45,25,25]
解释:
航班编号        1   2   3   4   5
预订记录 1 :   10  10
预订记录 2 :       20  20
预订记录 3 :       25  25  25  25
总座位数:      10  55  45  25  25
因此,answer = [10,55,45,25,25]


示例 2:

输入:bookings = [[1,2,10],[2,2,15]], n = 2
输出:[10,25]
解释:
航班编号        1   2
预订记录 1 :   10  10
预订记录 2 :       15
总座位数:      10  25
因此,answer = [10,25]

提示:

 

解题思路

看数据量这么大,暴力肯定要超时,所以用差分数组,以下是详细介绍
比如我们现在有一个数组arr,arr={0,2,5,4,9,7,10,0}

那么差分数组是什么呢?其实差分数组本质上也是一个数组,我们暂且定义差分数组为d,差分数组d的大小和原来arr数组大小一样,而且d[i]=arr[i]-arr[i-1](i≠0),且d[i]=0,它的含义是什么?就是原来数组i位置上的元素和i-1位置上的元素作差,得到的值就是d[i]的值。

所以,例子中的arr数组其对应的差分数组值如下图所示。

那么构造了这么个玩意有什么用呢?难道是来浪费宝贵的内存空间的?嗯,确实是来浪费宝贵的内存了,但是却换了时间上的高效。

现在我们有这么一个区间修改操作,即在区间1~4上,所有的数值都加上3.

我们不要傻傻地遍历arr数组的[1,4]范围,然后再分别给每个值加上3,我们此时更改差分数组d即可。

显而易见,差分数组d在[2,4]范围内的值都不用改变,只需要改变差分数组位置1和位置5的值即可,即d[1]=d[1]+3,而d[5]=d[5]-3,其余不变,为什么呢?因为差分数组的定义d[i]=arr[i]-arr[i-1]

现在,我们如何根据差分数组d来推测arr中某一个位置的值呢?

比如,此时,我们想知道arr[1]的值,我们不能直接通过arr[1]得到原来的值,因为在区间修改的操作中我们并没有修改arr的值,因此我们必须从前往后遍历递推,由于d[0]=arr[0]-0(我们定义arr[0]的前一个数为0),那么arr[0]=d[0]=0,又由于d[1]=arr[1]-arr[0]=5,那么arr[1]=5+arr[0]=5。以此类推,由于d[2]=arr[2]-arr[1]=3,所以arr[2]=3+arr[1]=8。

结论:总结下d数组反推arr数组的过程,d[i] += 3意味着给arr[i..]所有的元素都加了 3,然后d[j+1] -= 3又意味着对于arr[j+1..]减 3,那综合起来,是不是就是对arr[i..j]中的所有元素都加 3 了

代码实现

public class LeetCode59之航班预订统计 {

	
	int[] corpFlightBookings(int[][] bookings, int n) {
	    // arr 初始化为全 0
	    int[] arr = new int[n];
	    // 构造差分解法
	    Difference df = new Difference(arr);

	    for (int[] booking : bookings) {
	        // 注意转成数组索引要减一哦
	        int i = booking[0] - 1;
	        int j = booking[1] - 1;
	        int val = booking[2];
	        // 对区间 nums[i..j] 增加 val
	        df.increment(i, j, val);
	    }
	    // 返回最终的结果数组
	    return df.result();
	}
	
	
}


class Difference {
    // 差分数组
    private int[] d;

    public Difference(int[] nums) {
        assert nums.length > 0;
        d = new int[nums.length];
        // 构造差分数组
        d[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            d[i] = nums[i] - nums[i - 1];
        }
    }

    /* 给闭区间 [i,j] 增加 val(可以是负数)*/
    public void increment(int i, int j, int val) {
        d[i] += val;
        //最后一个数,对应的差分数组不需要减去val
        if (j + 1 < d.length) {
            d[j + 1] -= val;
        }
    }

    public int[] result() {
        int[] res = new int[d.length];
        // 根据差分数组构造结果数组
        res[0] = d[0];
        for (int i = 1; i < d.length; i++) {
            res[i] = res[i - 1] + d[i];
        }
        return res;
    }
}

ps:利用差分数组反推arr,而不是逐步累加arr在[i,j]区间的数据是避免超时的主要思路

类似题目

LeetCode 1094. 拼车
LeetCode 370. 区间加法(差分思想)
LeetCode 995. K 连续位的最小翻转次数(差分思想)
LeetCode 732. 我的日程安排表 III(差分思想)
LeetCode 1674. 使数组互补的最少操作次数(差分思想)
LeetCode 1854. 人口最多的年份(差分)
LeetCode 5767. 检查是否区域内所有整数都被覆盖(差分)
 

参考文章

https://blog.csdn.net/qq_31601743/article/details/105352885

https://blog.csdn.net/qq_21201267/article/details/106423509

https://mp.weixin.qq.com/s/9L6lz0XDZ9gi-d_iPrSs8Q
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

数据与后端架构提升之路

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

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

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

打赏作者

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

抵扣说明:

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

余额充值