LeetCode 1109. Corporate Flight Bookings【差分数组】


读完本文,你不仅学会了算法套路,还可以顺便去 LeetCode 上拿下如下题目:

http://ww1.sinaimg.cn/large/9b63ed6fgy1glvqyy7v1qj20xc0m8wgt.jpg

1109.航班预订统计(中等)

前文 前缀和技巧详解 写过的前缀和技巧是非常常用的算法技巧,前缀和主要适用的场景是原始数组不会被修改的情况下,频繁查询某个区间的累加和

没看过前文没关系,这里简单介绍一下前缀和,核心代码就是下面这段:

class PrefixSum {
    // 前缀和数组
    private int[] prefix;

    /* 输入一个数组,构造前缀和 */
    public PrefixSum(int[] nums) {
        prefix = new int[nums.length + 1];
        // 计算 nums 的累加和
        for (int i = 1; i < prefix.length; i++) {
            prefix[i] = prefix[i - 1] + nums[i - 1];
        }
    }

    /* 查询闭区间 [i, j] 的累加和 */
    public int query(int i, int j) {
        return prefix[j + 1] - prefix[i];
    }
}

img

prefix[i] 就代表着 nums[0..i-1] 所有元素的累加和,如果我们想求区间 nums[i..j] 的累加和,只要计算 prefix[j+1] - prefix[i] 即可,而不需要遍历整个区间求和。

本文讲一个和前缀和思想非常类似的算法技巧「差分数组」,差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减

比如说,我给你输入一个数组 nums,然后又要求给区间 nums[2..6] 全部加 1,再给 nums[3..9] 全部减 3,再给 nums[0..4] 全部加 2,再给…

一通操作猛如虎,然后问你,最后 nums 数组的值是什么?

常规的思路很容易,你让我给区间 nums[i..j] 加上 val,那我就一个 for 循环给它们都加上呗,还能咋样?这种思路的时间复杂度是 O(N),由于这个场景下对 nums 的修改非常频繁,所以效率会很低下。

这里就需要差分数组的技巧,类似前缀和技巧构造的 prefix 数组,我们先对 nums 数组构造一个 diff 差分数组,**diff[i]** 就是 nums[i] nums[i-1] 之差

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

img

通过这个 diff 差分数组是可以反推出原始数组 nums 的,代码逻辑如下:

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];
}

这样构造差分数组diff,就可以快速进行区间增减的操作,如果你想对区间 nums[i..j] 的元素全部加 3,那么只需要让 diff[i] += 3,然后再让 diff[j+1] -= 3 即可:

img

题目描述

知识点

查分数组

我的实现

结果

码前思考

  • 利用差分数组进行解题,diff[i] = num[i] - num[i-1]

代码实现

//使用差分数组解题
//diff[i] = num[i]-num[i-1]
class Solution {
public:
    vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
        vector<int> diff(n+2,0);

        int len = bookings.size();

        for(int idx=0;idx<len;idx++){
            int i = bookings[idx][0];
            int j = bookings[idx][1];
            int k = bookings[idx][2];
            diff[i] = diff[i]+k;
            diff[j+1] = diff[j+1]-k;      
        }

        vector<int> res;
        res.push_back(diff[1]);
        for(int i=2;i<=n;i++){
            res.push_back(res[i-2]+diff[i]);
        }
        return res;
    }
};

码后反思

  1. 写代码的时候有点不清醒,把数组下标写错了;
  2. 对于这道题,还有一个类似的题目是上下车问题,此时[i,j,k]表示有k个人从i站坐到j+1站下车,求解每一站有多少人。
  3. 从今天开始每日一题了,不然研究生毕业可找不到工作的呢~

文章作者: CarlYoung
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 CarlYoung !
 上一篇
毕设方向探索 毕设方向探索
方向一:GNN的Representation Learning改进应用领域首先,GNN作为一种神经网络(就像CNN,RNN这样的NN),它的应用领域有: Natural Language Processing Neural Machine
2020-12-22 CarlYoung
下一篇 
CCKS(全国知识图谱与语义计算大会) CCKS(全国知识图谱与语义计算大会)
今天跟老师聊了一下毕设的方向,老师提出了两方面的改进目标: 图神经网络的方法论上进行创新 从GNN的构图,表征学习等方面进行创新,这样一来,数据集不再是局限于金融数据集,可以是其他开源的数据集。 金融领域出发 从金融领域出发就不再只有反
2020-12-18 CarlYoung
  目录