【LeetCode】差分数组练习题

79 阅读6分钟

1094. 拼车

车上最初有 capacity 个空座位。车 只能 向一个方向行驶(也就是说,不允许掉头或改变方向

给定整数 capacity 和一个数组 trips ,  trip[i] = [numPassengersi, fromi, toi] 表示第 i 次旅行有 numPassengersi 乘客,接他们和放他们的位置分别是 fromi 和 toi 。这些位置是从汽车的初始位置向东的公里数。

当且仅当你可以在所有给定的行程中接送所有乘客时,返回 true,否则请返回 false。 

示例 1:

输入: trips = [[2,1,5],[3,3,7]], capacity = 4
输出: false

示例 2:

输入: trips = [[2,1,5],[3,3,7]], capacity = 5
输出: true

提示:

  • 1 <= trips.length <= 1000
  • trips[i].length == 3
  • 1 <= numPassengersi <= 100
  • 0 <= fromi < toi <= 1000
  • 1 <= capacity <= 105
class Solution {
public:
    int f[1005];
    void add(int l, int r, int v){
        f[l] += v;
        f[r] -= v;
    }
    bool carPooling(vector<vector<int>>& trips, int capacity) {
        for(auto c : trips){
            add(c[1], c[2], c[0]);
        }
        for(int i=1; i<1005; i++){
            f[i] += f[i-1];
        }
        for(auto c : f){
            if(c > capacity){
                return false;
            }
        }
        return true;
    }
};

1109. 航班预订统计

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

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

请你返回一个长度为 n 的数组 answer,里面的元素是每个航班预定的座位总数。

 

示例 1:

输入: bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
输出: [10,55,45,25,25]
解释:
航班编号        1   2   3   4   5
预订记录 110  10
预订记录 220  20
预订记录 325  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]

提示:

  • 1 <= n <= 2 * 104
  • 1 <= bookings.length <= 2 * 104
  • bookings[i].length == 3
  • 1 <= firsti <= lasti <= n
  • 1 <= seatsi <= 104
class Solution {
public:
    int f[20005];
    void add(int l, int r, int v){
        f[l] += v;
        f[r+1] -= v;
    }
    vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
        for(auto c : bookings){
            add(c[0], c[1], c[2]);
        }
        for(int i=1; i<=n; i++){
            f[i] += f[i-1];
        }
        vector<int> res;
        for(int i=1; i<=n; i++){
            res.push_back(f[i]);
        }
        return res;
    }
};

2381. 字母移位 II

给你一个小写英文字母组成的字符串 s 和一个二维整数数组 shifts ,其中 shifts[i] = [starti, endi, directioni] 。对于每个 i ,将 s 中从下标 starti 到下标 endi (两者都包含)所有字符都进行移位运算,如果 directioni = 1 将字符向后移位,如果 directioni = 0 将字符向前移位。

将一个字符 向后 移位的意思是将这个字符用字母表中 下一个 字母替换(字母表视为环绕的,所以 'z' 变成 'a')。类似的,将一个字符 向前 移位的意思是将这个字符用字母表中 前一个 字母替换(字母表是环绕的,所以 'a' 变成 'z' )。

请你返回对 s 进行所有移位操作以后得到的最终字符串。

示例 1:

输入: s = "abc", shifts = [[0,1,0],[1,2,1],[0,2,1]]
输出: "ace"
解释: 首先,将下标从 0 到 1 的字母向前移位,得到 s = "zac" 。
然后,将下标从 1 到 2 的字母向后移位,得到 s = "zbd" 。
最后,将下标从 0 到 2 的字符向后移位,得到 s = "ace"

示例 2:

输入: s = "dztz", shifts = [[0,0,0],[1,1,1]]
输出: "catz"
解释: 首先,将下标从 0 到 0 的字母向前移位,得到 s = "cztz" 。
最后,将下标从 1 到 1 的字符向后移位,得到 s = "catz"

提示:

  • 1 <= s.length, shifts.length <= 5 * 104
  • shifts[i].length == 3
  • 0 <= starti <= endi < s.length
  • 0 <= directioni <= 1
  • s 只包含小写英文字母。
class Solution {
public:
    int f[50005];
    void add(int l, int r, int v){
        if(v == 1){
            f[l]+=1;
            f[r+1] -=1;
        }else{
            f[l]+=-1;
            f[r+1] -=-1; 
        }
    }
    string shiftingLetters(string s, vector<vector<int>>& shifts) {
        for(auto c : shifts){
            add(c[0], c[1], c[2]);
        }
        int n = s.size();
        for(int i=1; i<n; i++) f[i] += f[i-1];
        for(int i=0; i<n; i++){
            s[i] = ('a' + (((s[i]-'a'+f[i] + 26)%26+26)%26));
        }
        return s;
    }
};

2406. 将区间分为最少组数

给你一个二维整数数组 intervals ,其中 intervals[i] = [lefti, righti] 表示  区间 [lefti, righti] 。

你需要将 intervals 划分为一个或者多个区间  ,每个区间  属于一个组,且同一个组中任意两个区间 不相交 。

请你返回 最少 需要划分成多少个组。

如果两个区间覆盖的范围有重叠(即至少有一个公共数字),那么我们称这两个区间是 相交 的。比方说区间 [1, 5] 和 [5, 8] 相交。

示例 1:

输入: intervals = [[5,10],[6,8],[1,5],[2,3],[1,10]]
输出: 3
解释: 我们可以将区间划分为如下的区间组:
- 第 1 组:[1, 5][6, 8] 。
- 第 2 组:[2, 3][5, 10] 。
- 第 3 组:[1, 10] 。
可以证明无法将区间划分为少于 3 个组。

示例 2:

输入: intervals = [[1,3],[5,6],[8,10],[11,13]]
输出: 1
解释: 所有区间互不相交,所以我们可以把它们全部放在一个组内。

提示:

  • 1 <= intervals.length <= 105
  • intervals[i].length == 2
  • 1 <= lefti <= righti <= 106
class Solution {
public:
    int f[1000005];
    void add(int l, int r){
        f[l] += 1;
        f[r+1] -=1;
    }
    int minGroups(vector<vector<int>>& intervals) {
        for(auto c : intervals){
            add(c[0], c[1]);
        }
        int res  = 0;
        for(int i=1; i<1000005; i++){
            f[i] += f[i-1];
            res = max(res, f[i]);
        }
        return res;
    }
};

2772. 使数组中的所有元素都等于零

给你一个下标从 0 开始的整数数组 nums 和一个正整数 k 。

你可以对数组执行下述操作 任意次 :

  • 从数组中选出长度为 k 的 任一 子数组,并将子数组中每个元素都 减去 1 。

如果你可以使数组中的所有元素都等于 0 ,返回  true **;否则,返回 **false **。

子数组 是数组中的一个非空连续元素序列。

示例 1:

输入: nums = [2,2,3,1,1,0], k = 3
输出: true
解释: 可以执行下述操作:
- 选出子数组 [2,2,3] ,执行操作后,数组变为 nums = [1,1,2,1,1,0] 。
- 选出子数组 [2,1,1] ,执行操作后,数组变为 nums = [1,1,1,0,0,0] 。
- 选出子数组 [1,1,1] ,执行操作后,数组变为 nums = [0,0,0,0,0,0] 。

示例 2:

输入: nums = [1,3,1,1], k = 2
输出: false
解释: 无法使数组中的所有元素等于 0 。

提示:

  • 1 <= k <= nums.length <= 10^5
  • 0 <= nums[i] <= 10^6
class Solution {
public:
    bool checkArray(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> d(n+1);
        d[0] = nums[0];
        for(int i=1; i<n; i++){
            d[i] = nums[i] - nums[i-1];
        }
        for(int i=0; i<=n-k; i++){
            if(d[i] == 0) continue;
            if(d[i] < 0) return false;
            d[i+k] += d[i];
        }
        for(int i=n-k+1; i<n; i++){
            if(d[i]) return false;
        }
        return true;
    }
};

中秋节快乐!