LeetCode-刷题记录-前缀和合集(本篇blog会持续更新哦~)

news/2024/7/22 3:57:17 标签: leetcode, 算法, 前缀和

一、前缀和(Prefix Sum)算法概述

前缀和算法通过预先计算数组的累加和,可以在常数时间内回答多个区间和相关的查询问题,是解决子数组和问题中的重要工具。

在这里插入图片描述

它的基本思想是通过预先计算和存储数组的前缀和,可以在 O(1) 的时间复杂度内计算任意子数组的和。

在这里插入图片描述

  1. 定义
    • 对于数组 nums,其前缀和 prefix[i] 定义为从数组起始位置到第 i 个元素的累加和。

在这里插入图片描述

  • 具体公式:prefix[i] = nums[0] + nums[1] + ... + nums[i]
  1. 计算方法
    • 首先,创建一个额外的数组或哈希表,用来存储每个位置的前缀和
    • 通过一次遍历数组,依次计算并填充这个数组或哈希表。

在这里插入图片描述

  1. 应用
    • 快速计算子数组和:通过前缀和,可以快速计算任意子数组的和。例如,子数组 nums[l...r] 的和可以通过 prefix[r] - prefix[l-1] 来计算,其中 lr 分别是子数组的左右边界。

在这里插入图片描述

  • 解决相关问题:例如,最大子数组和、和为特定值的子数组个数等问题,都可以通过前缀和算法高效解决。

在这里插入图片描述


二、前缀和习题合集

1. LeetCode 930 和相同的二元子数组

在这里插入图片描述

  • 思路:

假设原数组的前缀和数组为 sum,且子数组 (i,j] 的区间和为 goal,那么 sum[j]−sum[i]=goal。因此我们可以枚举 j ,每次查询满足该等式的 i 的数量。

用哈希表记录每一种前缀和出现的次数,假设我们当前枚举到元素 nums[j],我们只需要查询哈希表中元素 sum[j]−goal 的数量即可,这些元素的数量即对应了以当前 j 值为右边界的满足条件的子数组的数量。

  • pre[j] - pre[i]= goal —> pre[i] = pre[j] - goal

  • 如果存在前缀和为 pre[j] - goal(也就是pre[i])

  • 说明从某个位置 j 到当前位置 i 的子数组和为 goal

最后这些元素的总数量即为所有和为 goal 的子数组数量。

  • 代码:

class Solution {
    public int numSubarraysWithSum(int[] nums, int goal) {
        int n = nums.length; // 数组的长度
        Map<Integer,Integer> map = new HashMap<>(); // 使用哈希表来记录前缀和的出现次数
        int pre_J = 0; // 初始前缀和为0
        int ans = 0; // 计数器,用来记录符合条件的子数组个数
        
        for (int i = 0; i < n; i++) {
            map.put(preJ, map.getOrDefault(pre_J, 0) + 1); // 更新前缀和为 preJ 的出现次数
            pre_J += nums[i]; // 计算当前位置的前缀和
            //pre[j] - pre[i]= goal 
            //pre[i] = pre[j] - goal
            // 计算满足条件的子数组个数
            // 如果存在前缀和为 pre[j] - goal(也就是pre[i])
            //说明从某个位置 j 到当前位置 i 的子数组和为 goal
            ans += map.getOrDefault(pre_J - goal, 0);
        }
        
        return ans; // 返回符合条件的子数组个数
    }
}

2. LeetCode 560 和为K的子数组

在这里插入图片描述

  • 这里咋一看好像是可以用滑动窗口哈 ,但是发现数据里有负数。因为nums[i]可以小于0,也就是说右指针j向后移1位不能保证区间会增大,左指针i向后移1位也不能保证区间和会减小。

  • 思路 : 同上一题类似

前缀和 + 哈希

class Solution {
    public static int subarraySum(int[] nums, int k) {
        int n = nums.length; // 获取数组长度
        Map<Integer,Integer> map = new HashMap<>(); // 创建哈希表,用于存储前缀和及其出现次数
        int sum = 0; // 初始化前缀和为0
        int ans = 0; // 初始化结果为0
        map.put(sum,1); // 将初始的前缀和0放入哈希表,并设其出现次数为1
        // 遍历数组
        for(int num : nums){
            sum += num; // 计算当前位置的前缀和
            // 如果哈希表中存在前缀和为sum-k的项,则说明存在和为k的子数组 sum - (sum-k) = k
            if(map.containsKey(sum - k)){
                ans += map.get(sum - k); // 更新结果,累加前缀和为sum-k的子数组数量
            }
            map.put(sum, map.getOrDefault(sum, 0) + 1); // 更新哈希表,将当前前缀和放入,并更新出现次数
        }
        return ans; // 返回结果
    }
}
  • 初始时,将前缀和为 0 放入哈希表 map 中,表示在初始状态下存在一个前缀和为 0 的情况,出现次数为 1。

  • 如果 map 中存在 sum - k,则说明从之前的某个位置到当前位置的子数组的和为 k。这是因为 sum - (sum - k) = k

  • 如果存在这样的前缀和,则将该前缀和的出现次数累加到 ans 中。


3. LeetCode 523 连续的子数组和

在这里插入图片描述

在这里插入图片描述

  • 这里要用到数学知识——同余定理

在这里插入图片描述

  1. 前缀和的定义:preSum[i] 表示 nums 数组从 0 到 i 的元素之和。

    • 如果存在一个子数组 nums[j..i] (j < i),其和是 k 的倍数,则 preSum[i] - preSum[j-1] 必须是 k 的倍数。
  2. 利用余数的性质(同余定理)

    • 如果 preSum[i]preSum[j-1]k 取余得到相同的结果,即 (preSum[i] - preSum[j-1]) % k == 0,则存在这样的子数组。
    • a%k = b%k ,则 (a-b)%k =0 满足条件

在这里插入图片描述

  1. 使用哈希表记录余数: 使用哈希表来记录每个余数第一次出现的位置。

class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        int n = nums.length;
        int[] pre = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            pre[i] = pre[i - 1] + nums[i - 1]; // 计算前缀和
        }
        Set<Integer> set = new HashSet<>();
        for (int i = 2; i <= n; i++) {
            set.add(pre[i - 2] % k); // 将前缀和前两项的同余结果加入集合
            if (set.contains(pre[i] % k)) return true; // 如果当前前缀和对k取模的结果在集合中已经存在,说明找到了符合条件的子数组
        }
        return false; // 如果遍历完没有找到符合条件的子数组,返回false
    }
}


更新于:

在这里插入图片描述

本篇blog会持续更新哦~


http://www.niftyadmin.cn/n/5545567.html

相关文章

Three 圆柱坐标(Cylindrical)和 视锥体(Frustum)

圆柱坐标&#xff08;Cylindrical&#xff09; 圆柱坐标&#xff1a;一个点的cylindrical coordinates。英语&#xff1a;cylindrical coordinate system&#xff09;是一种三维坐标系统。它是二维极坐标系往 z-轴的延伸。添加的第三个坐标 &#x1d467; 专门用来表示 P 点离…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 7月9日,星期二

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年7月9日 星期二 农历六月初四 1、 最高检&#xff1a;对小摊小贩、小微企业处以高额罚款不符合法律精神。 2、 公安部&#xff1a;全国机动车保有量达4.4亿辆&#xff0c;驾驶人达5.32亿人。 3、 科技部&#xff1a;严禁将…

企业微信hook接口协议,移除群成员通知

移除群成员通知 返回示例 {"flag": 0, "receiver": 0, "sender_name": "", "is_room": 1, "server_id": 15318083, "send_time": 1687688952, "sender": 1688855749266556, "referid&…

从数字化营销与运营视角:看流量效果的数据分析

基于数据打通的“全链路”营销是当下的“时髦”&#xff0c;应用它的前提是什么&#xff1f;深度营销和运营的关键数据如何获得&#xff1f;如何利用数据进行更精准的营销投放&#xff1f;如何利用数据优化投放的效果&#xff1f;如何促进消费者的转化&#xff0c;以及激活留存…

【CSS01】CSS概述,使用样式的必要性,CSS语法及选择器

文章目录 一、什么是样式二、使用样式的必要性三、使用样式的几种方式四、CSS基本语法&#xff1a;五、CSS的注释六、CSS选择器——重点相关单词 一、什么是样式 概念&#xff1a; Cascade [kˈskeɪd] Style Sheet [ʃiːt] 级联样式单/表&#xff0c;层叠样式表 CSS有化腐…

mysql在linux系统下重置root密码

mysql在linux系统下重置root密码 登录服务器时候mysql密码忘记了&#xff0c;没办法只能重置&#xff0c;找了一圈&#xff0c;把行之有效的方法介绍在这里。 错误展示&#xff1a; 我还以为yes就可以了呢&#xff0c;这是不行的意思。 关掉mysql服务 sudo systemctl stop …

大语言模型系列-Transformer介绍

大语言模型系列&#xff1a;Transformer介绍 引言 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;Transformer模型已经成为了许多任务的标准方法。自从Vaswani等人在2017年提出Transformer以来&#xff0c;它已经彻底改变了NLP模型的设计。本文将介绍Transforme…

一款能在1060显卡上都能实现超分辨率的GAN模型——AuraSR

基于 GAN 的超级分辨率&#xff0c;用于提升生成图像的分辨率&#xff0c;是 GigaGAN 论文的变体&#xff0c;用于图像条件提升。Torch 实现基于非官方的 lucidrains/gigagan-pytorch 资源库。 下载 https://huggingface.co/fal/AuraSR github https://github.com/fal-ai/aura…