【算法优选】前缀和专题——叁

news2024/12/24 9:45:08

文章目录

  • 😎前言
  • 🌴[和为K的子数组](https://leetcode.cn/problems/subarray-sum-equals-k/description/)
    • 🚩题目描述
    • 🚩思路解析
    • 🚩代码实现
  • 🎄[和可被 K 整除的子数组](https://leetcode.cn/problems/subarray-sums-divisible-by-k/)
    • 🚩题目描述
    • 🚩解题须知:
    • 🚩算法思路:
    • 🚩代码实现
  • 🌲[连续数组](https://leetcode.cn/problems/contiguous-array/submissions/)
    • 🚩题目描述
    • 🚩思路解析
    • 🚩代码实现
  • 🍀[矩阵区域和](https://leetcode.cn/problems/matrix-block-sum/)
    • 🚩题目描述
    • 🚩思路解析
    • 🚩代码实现
  • ⭕总结

😎前言

含义

  • 前缀和实际上就是对于长度为n的数组,我们新建立一个数组长度为n+1,第i个元素的值为前i个元素的和(包括第i个元素)

特点

  1. 前缀和数组比原数组多一个长度。
  2. 前缀和的第0个元素的值为0。
  3. 根据前缀和数组的特点,求前缀和时。我们只需要用第i个元素的值+第i-1个前缀个数组的值就可能得到第i个前缀和数组的值。(这也是一种动态规划的思想)。

应用

  • 前缀和算法可以解决一些在数组中与连续有关的问题

🌴和为K的子数组

🚩题目描述

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。

子数组是数组中元素的连续非空序列。

  • 示例 1:
    输入:nums = [1,1,1], k = 2
    输出:2

  • 示例 2:
    输入:nums = [1,2,3], k = 3
    输出:2

class Solution {
    public int subarraySum(int[] nums, int k) {

    }
}

🚩思路解析

在这里插入图片描述
设 i 为数组中的任意位置,⽤ sum[i] 表⽰ [0, i] 区间内所有元素的和。

想知道有多少个「以 i 为结尾的和为 k 的⼦数组」,就要找到有多少个起始位置为 x1, x2,x3… 使得 [x, i] 区间内的所有元素的和为 k 。

那么 [0, x] 区间内的和是不是就是sum[i] - k 了。于是问题就变成:

  • 找到在 [0, i - 1] 区间内,有多少前缀和等于 sum[i] - k 的即可。

我们不⽤真的初始化⼀个前缀和数组,因为我们只关⼼在 i 位置之前,有多少个前缀和等于sum[i] - k 。因此,我们仅需⽤⼀个哈希表,⼀边求当前位置的前缀和,⼀边存下之前每⼀种前缀和出现的次数

🚩代码实现

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer, Integer> hash = new HashMap<Integer, Integer>();
        hash.put(0, 1);
        int sum = 0;
        int ret = 0;
        for(int x : nums)
        {
            sum += x; // 计算当前位置的前缀和
            ret += hash.getOrDefault(sum - k, 0); // 统计结果
            hash.put(sum, hash.getOrDefault(sum, 0) + 1); // 把当前的前缀和丢到哈希表⾥⾯
        }
        return ret;
    }
}

🎄和可被 K 整除的子数组

🚩题目描述

给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的(连续、非空) 子数组 的数目。

子数组 是数组的 连续 部分。

  • 示例 1:
    输入:nums = [4,5,0,-2,-3,1], k = 5
    输出:7
    解释:
    有 7 个子数组满足其元素之和可被 k = 5 整除:
    [4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]

  • 示例 2:
    输入: nums = [5], k = 9
    输出: 0

class Solution {
    public int subarraysDivByK(int[] nums, int k) {

    }
}

🚩解题须知:

  • 同余定理

如果 (a - b) % n == 0 ,那么我们可以得到⼀个结论: a % n = = b % n 。

⽤⽂字叙述就是,如果两个数相减的差能被n整除,那么这两个数对n取模的结果相同。

  • Java中负数取模的结果,以及如何修正「负数取模」的结果

Java中关于负数的取模运算,结果是「把负数当成正数,取模之后的结果加上⼀个负号」。

例如: -1 % 3 = -(1 % 3) = -1

因为有负数,为了防⽌发⽣「出现负数」的结果,以 (a % n + n) % n 的形式输出保证为正。

例如: -1 % 3 = (-1 % 3 + 3) % 3 = 2

🚩算法思路:

思路与和为K的⼦数组这道题的思路相似
在这里插入图片描述
设 i 为数组中的任意位置,⽤ sum[i] 表⽰ [0, i] 区间内所有元素的和。

  • 想知道有多少个「以 i 为结尾的可被 k 整除的⼦数组」,就要找到有多少个起始位置为 x1,x2, x3… 使得 [x, i] 区间内的所有元素的和可被 k 整除。

  • 设 [0, x - 1] 区间内所有元素之和等于 a , [0, i] 区间内所有元素的和等于 b ,可得(b - a) % k == 0 。

  • 由同余定理可得, [0, x - 1] 区间与 [0, i] 区间内的前缀和同余。于是问题就变成:

    • 找到在 [0, i - 1] 区间内,有多少前缀和的余数等于 sum[i] % k 的即可。

我们不⽤真的初始化⼀个前缀和数组,因为我们只关⼼在 i 位置之前,有多少个前缀和等于sum[i] - k 。因此,我们仅需⽤⼀个哈希表,⼀边求当前位置的前缀和,⼀边存下之前每⼀种前缀和出现的次数。

🚩代码实现

class Solution {
    public int subarraysDivByK(int[] nums, int k) {
        Map<Integer, Integer> hash = new HashMap<Integer, Integer>();
        hash.put(0 % k, 1);
        int sum = 0;
        int ret = 0;
        for(int x : nums)
        {
            sum += x; // 计算当前位置的前缀和
            int r = (sum % k + k) % k;
            ret += hash.getOrDefault(r, 0); // 统计结果
            hash.put(r, hash.getOrDefault(r, 0) + 1);
        }
        return ret;
    }
}

🌲连续数组

🚩题目描述

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

  • 示例 1:
    输入: nums = [0,1]
    输出: 2
    说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。

  • 示例 2:
    输入: nums = [0,1,0]
    输出: 2
    说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。

class Solution {
    public int findMaxLength(int[] nums) {

    }
}

🚩思路解析

稍微转化⼀下题⽬,就会变成我们熟悉的题:

  • 本题让我们找出⼀段连续的区间, 0 和 1 出现的次数相同。

  • 如果将 0 记为 -1 , 1 记为 1 ,问题就变成了找出⼀段区间,这段区间的和等于 0 。

  • 于是,就和560.和为K的⼦数组这道题的思路⼀样

在这里插入图片描述
设 i 为数组中的任意位置,⽤ sum[i] 表⽰ [0, i] 区间内所有元素的和。
想知道最⼤的「以 i 为结尾的和为 0 的⼦数组」,就要找到从左往右第⼀个 x1 使得 [x1, i] 区间内的所有元素的和为 0 。那么 [0, x1 - 1] 区间内的和是不是就是 sum[i] 了。于是问题就变成:

  • 找到在 [0, i - 1] 区间内,第⼀次出现 sum[i] 的位置即可。我们不⽤真的初始化⼀个前缀和数组,因为我们只关⼼在 i 位置之前,第⼀个前缀和等于 sum[i] 的位置。因此,我们仅需⽤⼀个哈希表,⼀边求当前位置的前缀和,⼀边记录第⼀次出现该前缀和的位置。

🚩代码实现

class Solution {
    public int findMaxLength(int[] nums) {
        Map<Integer,Integer> hashmap = new HashMap<>();
        hashmap.put(0,-1);
        int sum = 0;
        int ret = 0;
        for(int i = 0; i < nums.length; i++) {
            sum += (nums[i] == 0 ? -1 : 1);
            if(hashmap.containsKey(sum)) {
                ret = Math.max(ret,i - hashmap.get(sum));
            } else {
                hashmap.put(sum,i);
            }
        }
        return ret;
    }
}

🍀矩阵区域和

🚩题目描述

给你一个 m x n 的矩阵 mat 和一个整数 k ,请你返回一个矩阵 answer ,其中每个 answer[i][j] 是所有满足下述条件的元素 mat[r][c] 的和:

i - k <= r <= i + k, j - k <= c <= j + k 且(r, c) 在矩阵内。

  • 示例 1:
    输入:mat = [[1,2,3],[4,5,6],[7,8,9]], k = 1
    输出:[[12,21,16],[27,45,33],[24,39,28]]

  • 示例 2:
    输入:mat = [[1,2,3],[4,5,6],[7,8,9]], k = 2
    输出:[[45,45,45],[45,45,45],[45,45,45]]

class Solution {
    public int[][] matrixBlockSum(int[][] mat, int k) {

    }
}

🚩思路解析

⼆维前缀和的简单应⽤题,关键就是我们在填写结果矩阵的时候,要找到原矩阵对应区域的「左上⻆」以及「右下⻆」的坐标(推荐⼤家画图)

关于二维前缀和的求法,不懂得宝子可以去看看博主写的《【算法优选】 前缀和专题——壹》进行查看学习

左上⻆坐标: x1 = i - k,y1 = j - k ,但是由于会「超过矩阵」的范围,因此需要对 0 取⼀个 max 。因此修正后的坐标为: x1 = max(0, i - k), y1 = max(0, j - k) ;
右下⻆坐标: x1 = i + k,y1 = j + k ,但是由于会「超过矩阵」的范围,因此需要对 m- 1 ,以及 n - 1 取⼀个 min 。因此修正后的坐标为: x2 = min(m - 1, i + k),
y2 = min(n - 1, j + k)

然后将求出来的坐标代⼊到「⼆维前缀和矩阵」的计算公式上即可~(但是要注意下标的映射关系)

🚩代码实现

class Solution {
    public int[][] matrixBlockSum(int[][] mat, int k) {
        int m = mat.length, n = mat[0].length;
        // 1. 预处理前缀和矩阵
        int[][] dp = new int[m + 1][n + 1];
        for(int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + mat[i - 1][j - 1];
            }
        }
        // 2. 使⽤
        int[][] ret = new int[m][n];
        for(int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int x1 = Math.max(0, i - k) + 1;
                int y1 = Math.max(0, j - k) + 1;
                int x2 = Math.min(m - 1, i + k) + 1;
                int y2 = Math.min(n - 1, j + k) + 1;
                ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1];
            }
        }
        return ret;
    }
}

⭕总结

关于《【算法优选】 前缀和专题——叁》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1147789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【观察】Dell APEX云平台:引领多云时代上云新范式

毫无疑问&#xff0c;过去十多年是云计算发展的黄金十年&#xff0c;云计算理念不断被市场所接受&#xff0c;但随着企业上云深入和认知度的不断增加&#xff0c;摆在很多企业面前的选择题也发生了新变化&#xff0c;即从过去企业上云或不上云的纠结&#xff0c;转变成今天如何…

在pycharm中,远程操作服务器上的jupyter notebook

一、使用场景 现在我们有两台电脑&#xff0c;一台是拥有高算力的服务器&#xff0c;另一台是普通的轻薄笔记本电脑。如何在服务器上运行jupyter notebook&#xff0c;同时映射到笔记本电脑上的pycharm客户端中进行操作呢&#xff1f; 二、软件 pycharm专业版&#xff0c;jupy…

从一线到联合,克唑替尼在ALK阳性NSCLC治疗新旅程【医游记】

&#xff08;图片来源于网络&#xff09; 一、克唑替尼简介 克唑替尼(Crizotinib),商品名赛可瑞,是一款口服服用的小分子酪氨酸激酶抑制剂。克唑替尼最早于2011年被美国FDA批准用于ALK阳性晚期NSCLC的治疗。其主要靶点为间变淋巴瘤激酶(ALK)和ROS1(ROS proto-oncogene 1)融合…

Beyond Compare4 30天试用到期的2024最新解决办法

对于有文档对比需求的小伙伴们来说&#xff0c;Beyond Compare这款软件一定不陌生&#xff0c;这款软件是一款功能非常强大的文档对比软件。同时这款软件也是一款付费软件&#xff0c;需要用户付费才能够享有Beyond Compare的永久使用权&#xff0c;不过在付费之前&#xff0c;…

【OpenCV实现图像梯度,Canny边缘检测】

文章目录 概要图像梯度Canny边缘检测小结 概要 OpenCV中&#xff0c;可以使用各种函数实现图像梯度和Canny边缘检测&#xff0c;这些操作对于图像处理和分析非常重要。 图像梯度通常用于寻找图像中的边缘和轮廓。在OpenCV中&#xff0c;可以使用cv2.Sobel()函数计算图像的梯度…

部署私有仓库(笔记docker应用)

二&#xff1a;部署私有仓库 docker pull daocloud.io/library/registry:latest docker run --restartalways -d -p 5000:5000 daocloud.io/library/registry systemctl stop firewalld systemctl restart docker 宿主机ip端口 curl -I 127.0.0.1:5000 将镜像存放在仓…

[C++进阶篇]STL以及string的使用

目录 1. 什么是STL 2. STL库的六大组件 3. 标准库中的string类 3.3 对比size和capacity接口函数 size代表字符串有效长度 capacity代表字符串的实际长度 3.4 reserve&#xff0c;resize函数的使用 3.5 string类的访问和遍历 4. string的修改操作 5. insert和e…

3DMAX快速瓦片屋顶铺设插件使用方法详解

3DMAX快速瓦片屋顶铺设插件教程 3DMAX快速瓦片屋顶铺设插件&#xff0c;一键生成瓦片屋顶、瓦脊的插件&#xff0c;是一款非常实用的古风建筑建模插件。 【适用版本】 3dMax7或更新版本 【使用方法】 提示&#xff1a;建议使用本插件进行工作时&#xff0c;将3dMax单位设置为…

松下A6B伺服 马达不动问题解决

本人在用信捷XDH plc ethercat总线&#xff0c;连松下A6B伺服&#xff0c;轴配置完成轴调试时&#xff0c;出现能使能&#xff0c;但 马达不动的情况。 开始总怀疑时信捷PLC的原因&#xff0c;后面查明是输入口定义引起的。 用USB线连接伺服&#xff0c;打开PANAPARM软件,自…

[读论文] On Joint Learning for Solving Placement and Routing in Chip Design

0. Abstract 由于 GPU 在加速计算方面的优势和对人类专家的依赖较少&#xff0c;机器学习已成为解决布局和布线问题的新兴工具&#xff0c;这是现代芯片设计流程中的两个关键步骤。它仍处于早期阶段&#xff0c;存在一些基本问题&#xff1a;可扩展性、奖励设计和端到端学习范…

数据结构 | 顺序表专题

数据结构 | 顺序表专题 文章目录 数据结构 | 顺序表专题课前准备1. 目标2. 需要的储备知识3. 数据结构相关概念 开始顺序表1、顺序表的概念及结构2、顺序表分类3、动态顺序表的实现初始化顺序表打印顺序表内存容量的检查顺序表的尾插顺序表的尾删顺序表的头插顺序表的头删在顺序…

Beyond Compare比较规则设置 Beyond Compare怎么对比表格

在对文件进行比较时&#xff0c;文件夹内的文件可能存在不同类型、不同后缀名、不同内容等差异&#xff0c;这些差异会影响具体的比较结果&#xff0c;因此需要我们对软件的比较规则进行一些设置。接下来就让我们一起来学习一下Beyond Compare比较规则设置&#xff0c;Beyond C…

C语言-递归和迭代

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

ZYNQ连载07-PIN设备

ZYNQ连载07-PIN设备 1. 简述 RT-Thread PIN设备 这里参看RT-Thread提供的PIN设备管理接口&#xff0c;简单封装了几个接口函数。 2. 实现 #include "include/drv_gpio.h" #define LOG_TAG "drv_gpio" static XGpioPs xgpiops;void rt_pin_mode(rt_…

消息中间件——RabbitMQ(一)Windows/Linux环境搭建(完整版)

前言 最近在学习消息中间件——RabbitMQ&#xff0c;打算把这个学习过程记录下来。此章主要介绍环境搭建。此次主要是单机搭建&#xff08;条件有限&#xff09;&#xff0c;包括在Windows、Linux环境下的搭建&#xff0c;以及RabbitMQ的监控平台搭建。 环境准备 在搭建Rabb…

【AD9361 数字接口CMOS LVDSSPI】D 串行数据之SPI

【AD9361 数字接口CMOS &LVDS&SPI】D部分 接续 【AD9361 数字接口CMOS &LVDS&SPI】A 并行数据之CMOS 串行外设接口&#xff08;SPI&#xff09; SPI总线为AD9361的所有数字控制提供机制。每个SPI寄存器的宽度为8位&#xff0c;每个寄存器包含控制位、状态监视…

82 N皇后

N皇后 题解1 经典回溯 O(N! * N) 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在 同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的…

vue源码分析(六)——vnode 和 createElement的使用和作用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Vnode是什么&#xff1f;二、create-element.ts文件1.createElement 方法2. _createElement 方法&#xff08;1&#xff09;createEmptyVNode 方法&#xf…

STM32F103的中断

文章目录 STM32F103的NVICSTM32F103 的中断优先级分组 STM32F103的NVIC CM3 内核支持 256 个中断&#xff0c;其中包含了 16 个内核中断和 240 个外部中断&#xff0c;并且具有 256级的可编程中断设置。 CM3中每个中断通道都具备自己的8位中断优先级控制字节&#xff0c; 但ST…