GitHub_Trending/le/LeetCode-Book:前缀和与差分算法实战

GitHub_Trending/le/LeetCode-Book:前缀和与差分算法实战

【免费下载链接】LeetCode-Book 《剑指 Offer》 Python, Java, C++ 解题代码,LeetBook《图解算法数据结构》配套代码仓 【免费下载链接】LeetCode-Book 项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Book

1. 算法痛点与核心价值

你是否在处理数组区间问题时频繁遭遇以下困境?遍历嵌套导致超时(O(n²))、边界条件复杂难以调试、多次查询场景下重复计算?本文将系统讲解前缀和(Prefix Sum)与差分(Difference Array)两种预处理技术,带你实现从暴力解法到O(n)甚至O(1)的效率跃迁。

读完本文你将掌握

  • 前缀和数组构建与三类核心应用(区间和查询/子数组和问题/二维矩阵优化)
  • 差分算法的数学原理与实战技巧(区间增减/航班预订问题)
  • 基于LeetCode-Book项目源码的多语言实现(Python/Java/C++)
  • 10+企业级真题优化案例(字节跳动/阿里/腾讯高频面试题)

2. 前缀和算法:从重复计算到一次预处理

2.1 核心定义与数学本质

前缀和数组prefix是原数组nums的衍生数组,满足prefix[i] = nums[0] + nums[1] + ... + nums[i-1]。其本质是通过空间换时间,将任意区间和sum(nums[i..j])转化为prefix[j+1] - prefix[i]的O(1)计算。

mermaid

2.2 基础实现模板(Python/Java/C++)

def build_prefix(nums):
    n = len(nums)
    prefix = [0] * (n + 1)
    for i in range(n):
        prefix[i+1] = prefix[i] + nums[i]
    return prefix

# 区间和查询
def range_sum(prefix, i, j):
    return prefix[j+1] - prefix[i]
public int[] buildPrefix(int[] nums) {
    int n = nums.length;
    int[] prefix = new int[n + 1];
    for (int i = 0; i < n; i++) {
        prefix[i+1] = prefix[i] + nums[i];
    }
    return prefix;
}

public int rangeSum(int[] prefix, int i, int j) {
    return prefix[j+1] - prefix[i];
}
vector<int> buildPrefix(vector<int>& nums) {
    int n = nums.size();
    vector<int> prefix(n + 1, 0);
    for (int i = 0; i < n; i++) {
        prefix[i+1] = prefix[i] + nums[i];
    }
    return prefix;
}

int rangeSum(vector<int>& prefix, int i, int j) {
    return prefix[j+1] - prefix[i];
}

2.3 实战案例1:最大子数组和的前缀和解法

虽然LeetCode-Book中selected_coding_interview/docs/53. 最大子数组和.md采用动态规划解法,但前缀和结合哈希表可实现同等效率:

def max_sub_array(nums):
    prefix = 0
    min_prefix = 0
    max_sum = -float('inf')
    for num in nums:
        prefix += num
        max_sum = max(max_sum, prefix - min_prefix)
        min_prefix = min(min_prefix, prefix)
    return max_sum

原理对比表

解法时间复杂度空间复杂度核心思想
动态规划O(n)O(1)dp[i] = max(nums[i], dp[i-1]+nums[i])
前缀和+哈希O(n)O(1)max(prefix[j]-min_prefix[i]) (i<j)

2.4 实战案例2:和为s的连续正数序列

剑指Offer第57题II(sfo_57ii_consecutive_numbers_with_sum_s_s2.py)采用双指针法,其本质可视为前缀和的滑动窗口优化:

def find_continuous_sequence(target):
    i, j, s, res = 1, 2, 3, []
    while i < j:
        if s == target:
            res.append(list(range(i, j + 1)))
        if s >= target:
            s -= i
            i += 1
        else:
            j += 1
            s += j
    return res

前缀和视角解读:当窗口[i,j]的和s = prefix[j] - prefix[i-1],通过调整i/j实现O(n)复杂度,避免传统前缀和的O(n²)遍历。

3. 差分算法:区间增减的高效处理

3.1 算法定义与原理解析

差分数组diff满足diff[i] = nums[i] - nums[i-1]diff[0] = nums[0])。对区间[l,r]增减val时,仅需修改diff[l] += valdiff[r+1] -= val,最后通过前缀和恢复原数组。

mermaid

3.2 基础实现模板

def build_diff(nums):
    n = len(nums)
    diff = [0] * n
    diff[0] = nums[0]
    for i in range(1, n):
        diff[i] = nums[i] - nums[i-1]
    return diff

def range_add(diff, l, r, val):
    diff[l] += val
    if r + 1 < len(diff):
        diff[r+1] -= val

def restore_array(diff):
    n = len(diff)
    nums = [0] * n
    nums[0] = diff[0]
    for i in range(1, n):
        nums[i] = nums[i-1] + diff[i]
    return nums

3.3 实战案例:航班预订统计

LeetCode 1109题的差分解法(项目中未直接实现,基于模板扩展):

public int[] corpFlightBookings(int[][] bookings, int n) {
    int[] diff = new int[n + 2]; // 避免r+1越界
    for (int[] book : bookings) {
        int l = book[0], r = book[1], val = book[2];
        diff[l] += val;
        diff[r+1] -= val;
    }
    // 恢复原数组
    int[] res = new int[n];
    res[0] = diff[1];
    for (int i = 1; i < n; i++) {
        res[i] = res[i-1] + diff[i+1];
    }
    return res;
}

4. 高级应用与项目源码关联

4.1 二维前缀和:矩阵区域和

虽然项目中未直接提供,但可基于LCR 130. 衣橱整理.md的矩阵遍历思想扩展:

vector<vector<int>> build2DPrefix(vector<vector<int>>& matrix) {
    int m = matrix.size(), n = matrix[0].size();
    vector<vector<int>> prefix(m+1, vector<int>(n+1, 0));
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            prefix[i][j] = matrix[i-1][j-1] + prefix[i-1][j] + prefix[i][j-1] - prefix[i-1][j-1];
        }
    }
    return prefix;
}

4.2 前缀和+位运算:寻找单身数字

剑指Offer第56题I(sfo_56i_single_number_i_s1.py)可结合前缀异或和优化:

def singleNumbers(nums):
    xor_sum = 0
    for num in nums:
        xor_sum ^= num
    # 后续分组逻辑省略...

5. 学习路线与项目实践指南

5.1 必刷题目清单(基于项目目录)

  1. 前缀和入门selected_coding_interview/docs/53. 最大子数组和.md
  2. 差分应用sword_for_offer/docs/剑指 Offer 57 - II. 和为 s 的连续正数序列.md
  3. 二维扩展leetbook_ioa/docs/LCR 130. 衣橱整理.md
  4. 综合实战selected_coding_interview/docs/304. 二维区域和检索 - 矩阵不可变.md(需自行实现)

5.2 性能优化 checklist

  • ✅ 前缀和数组大小设为n+1,避免边界判断
  • ✅ 差分修改时注意r+1是否越界
  • ✅ 多次查询场景优先考虑前缀和预处理
  • ✅ 区间修改密集场景必用差分算法

5.3 企业面试高频考点

  • 前缀和与哈希表结合的子数组和问题(字节跳动)
  • 差分算法的航班预订/座位预约实现(阿里)
  • 二维前缀和的图像模糊处理(腾讯)

6. 总结与展望

前缀和与差分作为两种预处理技术,在数组区间问题中展现出"一次预处理,多次高效查询"的强大能力。通过LeetCode-Book项目中的实战案例分析可见,这两种算法虽未被单独成册讲解,但其思想已渗透在动态规划、双指针等多种解题方法中。

建议结合项目中selected_coding_interview/docs/3. 无重复字符的最长子串.md等滑动窗口题目,进一步体会前缀和思想的变体应用。未来刷题时,可尝试用前缀和重解已AC的子数组问题,培养算法优化思维。

收藏本文,关注项目更新,下期将带来《贪心算法在区间调度中的极致优化》。

【免费下载链接】LeetCode-Book 《剑指 Offer》 Python, Java, C++ 解题代码,LeetBook《图解算法数据结构》配套代码仓 【免费下载链接】LeetCode-Book 项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Book

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值