什么是差分数组?

文章介绍了差分数组的概念,如何通过差分数组快速计算数组元素的变化,以及在LeetCode例题中如何使用差分数组进行航班预订统计。展示了两种处理数组增减操作的方法:直接和通过差分数组优化。


定义

对于数组 A[n],它的差分数组为:
d i f f [ i ] = { A [ i ] , i = = 0 A [ i ] − A [ i − 1 ] , 0 < i < n diff[i]=\begin{cases} A[i],&i==0 \\ A[i]-A[i-1],&0<i<n \end{cases} diff[i]={A[i],A[i]A[i1],i==00<i<n
显然,通过差分数组 diff[n],可以求得 A[n] 中的某一具体元素:
A [ i ] = { d i f f [ i ] , i = = 0 d i f f [ i ] + A [ i − 1 ] , 0 < i < n A[i]=\begin{cases} diff[i],&i==0 \\ diff[i]+A[i-1],&0<i<n \end{cases} A[i]={diff[i],diff[i]+A[i1],i==00<i<n


应用

  1. 数组 A[n] 从下标 j 开始的元素,都增加 v。(即 A[j, j+1, ..., n-1] += v)
    d i f f [ j ] = d i f f [ j ] + v diff[j]=diff[j]+v diff[j]=diff[j]+v
  2. 数组 A[n] 在区间 [L, R] 内的元素,都增加 v。(即 A[L, L+1, ..., R] += v)
    { d i f f [ L ] = d i f f [ L ] + v d i f f [ R + 1 ] = d i f f [ R + 1 ] − v \begin{cases} diff[L]=diff[L]+v \\ diff[R+1]=diff[R+1]-v \end{cases} {diff[L]=diff[L]+vdiff[R+1]=diff[R+1]v
  3. 数组 A[n] 中的某一元素 A[j] 增加 v
    { d i f f [ j ] = d i f f [ j ] + v d i f f [ j + 1 ] = d i f f [ j + 1 ] − v \begin{cases} diff[j] = diff[j]+v \\ diff[j+1]=diff[j+1]-v \end{cases} {diff[j]=diff[j]+vdiff[j+1]=diff[j+1]v

例题

LeetCode1109. 航班预订统计
暴力解

int* corpFlightBookings(int** bookings, int bookingsSize, int* bookingsColSize, int n, int* returnSize) {
    int *ret = (int*)calloc(n, sizeof(int));
    memset(ret, 0, n * sizeof(int));

    for (int i = 0; i < bookingsSize; i++)
    {
        for (int j = bookings[i][0] - 1; j < bookings[i][1]; j++)
        {
            ret[j] += bookings[i][2];
        }
    }
    *returnSize = n;

    return ret;
}

差分数组

int* corpFlightBookings(int** bookings, int bookingsSize, int* bookingsColSize, int n, int* returnSize) {
    int *ret = (int*)calloc(n, sizeof(int)), *diff = (int*)calloc(n, sizeof(int));
    memset(ret, 0, n * sizeof(int));
    memset(diff, 0, n * sizeof(int));
    *returnSize = n;

    for (int i = 0; i < bookingsSize; i++)
    {
        diff[bookings[i][0] - 1] += bookings[i][2];
        if (bookings[i][1] < n)
            diff[bookings[i][1]] -= bookings[i][2];
    }
    ret[0] = diff[0];
    for (int i = 1; i < n; i++)
        ret[i] = diff[i] + ret[i - 1];

    return ret;
}

<think>嗯,用户问的是多表查询,这个我得先理清楚基本概念。首先,多表查询应该是在数据库中同时从多个表中获取数据的操作吧。常见的比如关联查询,可能需要用到JOIN或者子查询之类的。 接下来得想想为什么需要多表查询。通常数据库设计的时候会做规范化,把数据分散到不同的表中,避免冗余。但查询的时候,用户可能需要的信息分布在多个表里,这时候就得用多表查询来组合数据。例如,订单表和客户表分开,查订单时带上客户信息就需要联表。 然后,多表查询的类型有哪些呢?内连接、外连接(左、右、全)、交叉连接这些应该都算。还有可能用户会问到不同的JOIN区别,比如INNER JOIN只返回匹配的行,LEFT JOIN返回左表所有行即使右表没有匹配。可能需要举个例子说明。 还要注意多表查询的语法,比如在SQL中如何使用JOIN关键字,ON后面跟连接条件。还有可能涉及到的性能问题,比如连接过多表或者没有索引会导致查询变慢。不过用户可能暂时不需要深入性能优化,但提一下注意事项也是好的。 另外,子查询和多表连接的区别是什么?有时候子查询可以替代多表连接,但执行效率可能有差异。比如,相关子查询和独立子查询的应用场景。不过可能对于初学者来说,先掌握JOIN会更直接。 还有,多表查询的应用场景。比如报表生成、数据分析,需要聚合多个表的数据。或者在实际业务中,比如电商系统中的订单、商品、用户信息的联合查询。 可能用户也会遇到多表查询中的常见错误,比如笛卡尔积,因为没有指定连接条件导致结果集过大。这时候需要强调ON条件的重要性。或者表别名的作用,简化SQL语句,避免列名冲突。 最后,是否需要举个实际的例子?比如有两个表,学生表和成绩表,通过学生ID连接,查询学生姓名和成绩。这样用户能更直观地理解。 还要考虑用户可能的背景,如果是刚学SQL的新手,可能需要更基础的例子和解释,避免使用太专业的术语。或者他们可能在使用特定的数据库系统,比如MySQL、PostgreSQL,虽然多表查询语法大体相同,但某些细节可能有差异,不过这个问题可能暂时不需要深入。 总结一下,回答的结构应该是先定义,再为什么需要,然后是类型和示例,最后注意事项。这样结构清晰,用户能逐步理解。</think>### 什么是多表查询? 多表查询是数据库操作中**从多个关联表中提取和组合数据**的技术。通过分析表之间的关系(如主键-外键关联),将分散在不同表中的数据合并为有意义的结果。 --- ### 为什么需要多表查询? 1. **规范化存储** 数据库设计通常遵循规范化原则,将数据拆分到不同表中以减少冗余。例如: - `订单表`存储订单信息 - `客户表`存储客户信息 查询订单时需要关联客户姓名,就必须联合查询两表。 2. **提高数据关联性** 避免信息孤立,例如: - 商品表 + 库存表 → 查询商品实时库存 - 学生表 + 成绩表 → 生成学生成绩单 --- ### 多表查询的核心方法 #### 1. **连接查询(JOIN)** - **内连接(INNER JOIN)** 仅返回匹配条件的记录 ```sql SELECT 学生.姓名, 成绩.分数 FROM 学生 INNER JOIN 成绩 ON 学生.学号 = 成绩.学号; ``` - **左连接(LEFT JOIN)** 保留左表所有记录,右表无匹配时填充`NULL` ```sql SELECT 客户.姓名, 订单.金额 FROM 客户 LEFT JOIN 订单 ON 客户.ID = 订单.客户ID; ``` - **右连接(RIGHT JOIN)** 与左连接相反,保留右表所有记录。 - **全连接(FULL OUTER JOIN)** 返回两表所有记录(部分数据库不支持)。 #### 2. **子查询(Subquery)** 将查询结果作为另一个查询的条件或数据源: ```sql SELECT 姓名 FROM 学生 WHERE 学号 IN ( SELECT 学号 FROM 成绩 WHERE 分数 > 90 ); ``` --- ### 注意事项 1. **避免笛卡尔积** 未指定连接条件时,会返回所有可能的行组合(例如表A有10行,表B有20行 → 输出200行),需严格使用`ON`或`WHERE`约束。 2. **性能优化** - 为连接字段建立索引 - 减少不必要的表连接数量 3. **别名简化** 使用表别名提高可读性: ```sql SELECT s.姓名, c.课程名 FROM 学生 AS s JOIN 选课 AS sc ON s.学号 = sc.学号 JOIN 课程 AS c ON sc.课程号 = c.课程号; ``` --- ### 示例场景 **需求**:查询购买了“手机”类商品的客户信息 ```sql SELECT 客户.姓名, 订单.下单时间 FROM 客户 JOIN 订单 ON 客户.ID = 订单.客户ID JOIN 商品 ON 订单.商品ID = 商品.ID WHERE 商品.类别 = '手机'; ``` 通过多表查询,可以灵活应对复杂业务场景,是数据库应用的核心技能之一。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值