《算法零基础100讲》(第59讲) 前缀和 线性前缀和统计

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法零基础100讲》(第59讲) 前缀和 线性前缀和统计相关的知识,希望对你有一定的参考价值。

零、写在前面

  这是《算法零基础100讲》 专栏打卡学习的第五十九天了。
  每天打卡的题,做不出来没关系,因为困难的题涉及知识点较多,后面还是会开放出来的,就像昨天的 最大公约数 那道题今天还是会有,所以不要着急,内容能看懂,能自己分析,能做出简单题,就可以打卡。
  在刷题的过程中,总结自己遇到的坑点,写出 「 解题报告 」 供他人学习,也是一种自我学习的方式。这就是经典的帮助他人的同时,成就自己。目前, 「 万人千题 」 社区 每天都会有五六篇高质量的 「 解题报告 」 被我 「 加精 」。如果觉得自己有能力的,也可以来发布你的 「 解题报告 」。千万级流量,你我共同拥有。

一、概念定义

  有关前缀和的概念,在《算法零基础100讲》(第57讲) 前缀和(一) 线性前缀和入门 中已经较为清晰的阐述,今天我们来学习它的一些应用。

1、问题引入

  考虑这么一个问题,一开始我们有一个下标从零开始的整数区间,区间里的每个格子的值都为0,如下:

然后,我们选择一个区间 [ 1 , 5 ] [1, 5] [1,5],对区间内的每个值都加上 3,变成:

再选择一个区间 [ 3 , 6 ] [3, 6] [3,6],对区间内的每个值都加上 2,变成:

最后,求每个格子对应的值是多少。对于这么一个问题,我们来分析一下。

2、最坏时间复杂度

  假设区间的长度为 n n n,总共 m m m 才累加操作,那么最坏情况下就是每次操作都需要对 n n n 个数进行累加。所以,朴素算法下,最坏的时间复杂度为 O ( m n ) O(mn) O(mn)

3、优化算法

  当选择区间 [ l , r ] [l, r] [l,r] 累加一个值 x x x 时,我们可以在 l l l 的格子加上 x x x,在 r + 1 r+1 r+1 的格子减去 x x x。例如,在 [ 1 , 5 ] [1,5] [1,5] 累加 3 这个操作可以简化成在 1 1 1 的位置累加 3,而在 5 + 1 = 6 5+1=6 5+1=6 的位置减去 3,如下所示:

  这样就把每次区间操作的 O ( n ) O(n) O(n) 转换成了 O ( 1 ) O(1) O(1)
  最后,统计一次前缀和,就是我们要求的每个格子的累加和了。

二、题目描述

  这里有 n n n 个航班,它们分别从 1 1 1 n n n 进行编号。有一份航班预订表 b o o k i n g s bookings bookings ,表中第 i i i 条预订记录 b o o k i n g s [ i ] = [ f i r s t i , l a s t i , s e a t s i ] bookings[i] = [first_i, last_i, seats_i] bookings[i]=[firsti,lasti,seatsi] 意味着在从 f i r s t i first_i firsti l a s t i last_i lasti 的 每个航班 上预订了 s e a t s i seats_i seatsi 个座位。请你返回一个长度为 n n n 的数组,里面的元素是每个航班预定的座位总数。

三、算法详解

  对于每个区间, [ f i r s t i , l a s t i ] [first_i, last_i] [firsti,lasti],直接在 f i r s t i first_i firsti 的位置加上 s e a t s i seats_i seatsi,并且在 l a s t i + 1 last_i+1 lasti+1 的位置减去 s e a t s i seats_i seatsi,最后一次前缀和统计就是答案。

四、源码剖析

int* corpFlightBookings(int** bookings, int bookingsSize, int* bookingsColSize, int n, int* returnSize)
    int *sum = (int *)malloc(sizeof(int) * (n+2));
    int *ret = (int *)malloc(sizeof(int) * (n+2));
    int i;
    int f, l, s;
    memset(sum, 0, sizeof(int) * (n+2));
    for(i = 0; i < bookingsSize; ++i) 
        f = bookings[i][0];
        l = bookings[i][1];
        s = bookings[i][2];
        sum[f] += s;                   // (1)
        sum[l+1] -= s;                 // (2)
    
    *returnSize = 0;
    for(i = 1; i <= n; ++i) 
        if(i>1)
            sum[i] += sum[i-1];        // (3)
        ret[ (*returnSize)++ ] = sum[i];
    
    return ret;


  • ( 1 ) (1) (1) 左区间的位置加上 s s s
  • ( 2 ) (2) (2) 右区间+1 的位置减去 s s s
  • ( 3 ) (3) (3) 统计前缀和就是答案;

五、推荐专栏

🌳《画解数据结构》🌳

画解顺序表

六、习题练习

序号题目链接难度
1连续的子数组和★★☆☆☆
2子数组和排序后的区间和★★☆☆☆
3可获得的最大点数★★☆☆☆
4有序数组中差绝对值之和★★☆☆☆
5航班预订统计★★☆☆☆
👇🏻 添加 博主 参加九日集训👇🏻

以上是关于《算法零基础100讲》(第59讲) 前缀和 线性前缀和统计的主要内容,如果未能解决你的问题,请参考以下文章

《算法零基础100讲》(第57讲) 前缀和 线性前缀和入门

《算法零基础100讲》(第60讲) 前缀和 线性前缀和配合哈希表

《算法零基础100讲》(第61讲) 前缀和 二维前缀和

《算法零基础100讲》(第17讲) 线性枚举 - 最值算法

题解《算法零基础100讲》(第17讲) 线性枚举 - 最值算法(java版)

题解《算法零基础100讲》(第18讲) 线性枚举 - 统计法入门(java版)