1. 差分数组简介

前缀和数组使用与数组中的元素不改变的情况,而差分数字与之相反,适用于数组元素经常改变的情况。比如存在一个数组nums, 给定一个区间[i,j],在给定一个属val,val值可正可负,将区间[i,j]内的元素都加上val, 反复进行如上操作,求解数组中最后的元素值是多少
diff[i]=nums[i]-nums[i-1] 特别注意的一点是diff[0]=nums[0] 之所以设置diff[0]=nums[0],是因为后面我们需要通过差分数组反推出数组

  1. for(int i=1;i<nums.length;i++)
  2. {
  3. nums[0]=diff[0];
  4. nums[i]=nums[i-1]+diff[i];
  5. }

假设现在给出一个区间[i,j],并给出一个数字3, 我们只需要将diff[i]+3, 将diff[j+1]-3,即可达到将区间[i,j]内的元素值都加上3的效果

2. 差分数组实战1

图片.png

这一题本质上是一个差分数组的模板题,特殊点: 原始数组nums中元素都是0,每次加的值都是正数

  1. 直接套用模板

    1. class Solution {
    2. int []diff;
    3. int []nums;
    4. public int[] corpFlightBookings(int[][] bookings, int n) {
    5. diff=new int[n];
    6. nums=new int[n];
    7. for(int []booking:bookings)
    8. {
    9. int i=booking[0]-1;//位置和下标差1
    10. int j=booking[1]-1;
    11. int val=booking[2];
    12. increase(i,j,val);
    13. }
    14. getResult();
    15. return nums;
    16. }
    17. public void createDiff(int []nums)
    18. {
    19. diff[0]=nums[0];
    20. for(int i=1;i<nums.length;i++)
    21. diff[i]=nums[i]-nums[i-1];
    22. }
    23. public void increase(int i,int j,int val)
    24. {
    25. diff[i]+=val;
    26. if(j+1<nums.length)
    27. diff[j+1]-=val;
    28. }
    29. public void getResult()
    30. {
    31. nums[0]=diff[0];
    32. for(int i=1;i<nums.length;i++)
    33. {
    34. nums[i]=nums[i-1]+diff[i];
    35. }
    36. }
    37. }
    38. //O(m+n) O(m)是处理预定记录 O(n)是反推原数组
    39. //O(n) 保存原来数组的空间消耗
  2. 优化空间

    对于上面的代码可以省去nums数组,由于原始数组元素都是0,所以差分数组的初始值都是0,其实对于一般情况,最后用差分数组来替代nums数组也是可以的,因为 nums[0]=diff[0] diff[0] nums[1]=nums[0]+diff[1] diff[1]=diff[0]+diff[1] nums[2]=nums[1]+diff[2] diff[2]=diff[1]+diff[2]

  1. class Solution {
  2. int []diff;
  3. public int[] corpFlightBookings(int[][] bookings, int n) {
  4. diff=new int[n];
  5. for(int []booking:bookings)
  6. {
  7. int i=booking[0]-1;
  8. int j=booking[1]-1;
  9. int val=booking[2];
  10. increase(i,j,val);
  11. }
  12. getResult();
  13. return diff;
  14. }
  15. // public void createDiff(int []nums)
  16. // {
  17. // diff[0]=nums[0];
  18. // for(int i=1;i<nums.length;i++)
  19. // diff[i]=nums[i]-nums[i-1];
  20. // }
  21. public void increase(int i,int j,int val)
  22. {
  23. diff[i]+=val;
  24. if(j+1<diff.length)
  25. diff[j+1]-=val;
  26. }
  27. public void getResult()
  28. {
  29. for(int i=1;i<diff.length;i++)
  30. {
  31. diff[i]=diff[i-1]+diff[i];
  32. }
  33. }
  34. }
  35. //O(m+n) O(m)是处理预定记录 O(n)是反推原数组
  36. //O(1) 保存答案的数组不纳入空间消耗

3. 差分数组实战2

图片.png

记上车地点为i,下车地点为j, 人数为val, 实质上就是在区间[i,j-1]范围内对数组加上val(原始数组值都是0),在进行了所有区间的操作之后,只需要判断数组中的每一个元素是否大capacity, 只要有一个大于capacity就超载

  1. class Solution {
  2. int diff[]=new int[1000];//车站数目不超过1000
  3. //最初的状态车是空的 可以看成在各个车站时车站上面的都是空的 因此nums数组为0
  4. //可以不考虑nums数组
  5. public boolean carPooling(int[][] trips, int capacity) {
  6. for(int []trip:trips)
  7. {
  8. int val=trip[0];
  9. //因为trip[2]时已经下车 所以可以看成在区间[trip[1],trip[2]-1]增加人数
  10. int i=trip[1];
  11. int j=trip[2]-1;
  12. increase(i,j,val);
  13. }
  14. getResult();
  15. //最后要求达到每一站时都不能超载
  16. for(int i=0;i<diff.length;i++)
  17. if(diff[i]>capacity)
  18. return false;
  19. return true;
  20. }
  21. public void increase(int i,int j,int val)
  22. {
  23. diff[i]+=val;
  24. if(j+1<diff.length)
  25. diff[j+1]-=val;
  26. }
  27. public void getResult()
  28. {
  29. for(int i=1;i<diff.length;i++)
  30. {
  31. diff[i]=diff[i-1]+diff[i];
  32. }
  33. }
  34. }
  35. //O(n)
  36. //O(n)