【唐叔学算法】第六天:前缀和-简化数组问题的黄金钥匙

45 阅读4分钟

引言

在算法的世界中,前缀和算法是一种解决数组相关问题的高效方法。它通过预先计算数组元素的累积和,从而在查询时能够快速得到答案。作为一名Java技术博主,唐叔今天将带大家深入了解前缀和的工作原理,以及它在解决实际问题中的强大之处。通过本文,你将学会如何运用前缀和来处理各种数组问题,并在LeetCode上的应用实例中,掌握其解题技巧。

前缀和算法概述

定义

前缀和(Prefix Sum)是一种常见的算法技巧,主要用于处理数组或序列的连续子区间求和问题。通过构建一个前缀和数组,我们可以快速查询任意连续区间的和,从而在一定程度上优化时间复杂度。

基本原理

假设有一个数组 arr,其前缀和数组 prefix 定义如下:

  • prefix[i] 表示从数组起点到位置 i 的元素之和。

  • 因此,前缀和数组 prefix 可以定义为:

    prefixSum[i] = arr[0] + arr[1] + ... + arr[i]

计算任意区间和

计算任意区间和 arr[l] + arr[l+1] + ... + arr[r] 可以通过前缀和快速得到:arr[l] + arr[l + 1] + ... + arr[r] = prefix[r] - prefix[l - 1]

例子

假设有数组 arr = [1, 2, 3, 4, 5],构建前缀和数组 prefix 如下:

  • prefix[0] = 1
  • prefix[1] = 1 + 2 = 3
  • prefix[2] = 1 + 2 + 3 = 6
  • prefix[3] = 1 + 2 + 3 + 4 = 10
  • prefix[4] = 1 + 2 + 3 + 4 + 5 = 15

那么,求区间和 arr[1] + arr[2] + arr[3] 就可以通过前缀和数组计算: arr[1] + arr[2] + arr[3] = prefix[3] - prefix[0] = 10 - 1

实现步骤

使用前缀和解决问题的一般步骤如下:

  1. 「初始化前缀和数组」:创建一个与原数组长度相同的前缀和数组,并将 prefix[0] 初始化为 arr[0]
  2. 「构建前缀和数组」:通过遍历原数组,计算每个位置的前缀和。
  3. 「查询区间和」:通过前缀和数组快速计算任意区间的和。

注意事项

  • 「初始化」:确保 prefix[0] 正确初始化为 arr[0],避免后续计算出错。
  • 「边界条件」:处理边界条件时要特别小心,确保不会越界。
  • 「空间复杂度」:前缀和数组需要额外的存储空间,但通常不会对整体性能产生太大影响。

应用场景

前缀和常用于解决以下问题:

  • 快速计算数组任意区间的和。
  • 确定数组中某个元素的累积和。
  • 优化双指针问题。

LeetCode实战:前缀和算法应用

入门题:1480. 一维数组的动态和

题目链接:1480. 一维数组的动态和

题目描述:给你一个数组 nums,返回其动态和 runningSum,其中 runningSum[i] = sum(nums[0]…nums[i])

Java代码实现

class Solution {
    public int[] runningSum(int[] nums) {
        int n = nums.length;
        int[] runningSum = new int[n];
        runningSum[0] = nums[0];
        for (int i = 1; i < n; i++) {
            runningSum[i] = runningSum[i - 1] + nums[i];
        }
        return runningSum;
    }
}

解题思路

这个问题可以直接通过前缀和来解决。我们遍历数组,逐步计算每个位置的前缀和,并将其存储在结果数组中。

中等题:560. 和为K的子数组

题目链接:560. 和为K的子数组

题目描述:给定一个整数数组 nums 和一个整数 k,返回数组中和为 k 的连续子数组的个数。

Java代码实现

import java.util.HashMap;
import java.util.Map;

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map prefixCount = new HashMap<>();
        prefixCount.put(01); // 初始化前缀和为0的情况
        int prefix = 0;
        int count = 0;

        for (int num : nums) {
            prefix += num;
            if (prefixCount.containsKey(prefix - k)) {
                count += prefixCount.get(prefix - k);
            }
            prefixCount.put(prefix, prefixCount.getOrDefault(prefix, 0) + 1);
        }

        return count;
    }
}

解题思路

这个问题可以用前缀和结合哈希表来解决。我们遍历数组,计算每个位置的前缀和,并将前缀和存入哈希表中。对于每个前缀和 prefix,检查哈希表中是否存在 prefix - k,如果存在,则说明存在一个子数组的和为 k

更多LeetCode题目推荐

如果您对前缀和算法感兴趣,希望挑战更多题目,以下是一些LeetCode上推荐的题目:

结语

通过本文的学习,相信大家对前缀和算法有了更深入的理解。前缀和算法虽然简单,但在实际应用中却非常高效,特别是在处理数组区间求和问题时。希望各位读者朋友能够在实践中灵活运用前缀和算法,解决更多的编程问题。

如果有任何疑问或建议,欢迎在评论区留言交流!下次见!


希望这篇文章能够帮助大家更好地理解和应用前缀和算法。如果喜欢这篇文章,别忘了点赞和分享哦!😊