前缀和算法

【模板】前缀和

image.png

题目链接:前缀和

算法思路

image.png
先预处理出来⼀个「前缀和」数组:

  • ⽤ dp[i] 表⽰: [1, i] 区间内所有元素的和,那么 dp[i - 1] ⾥⾯存的就是 [1, i - 1] 区间内所有元素的和,那么:可得递推公式: dp[i] = dp[i - 1] + arr[i] ;
  • 使⽤前缀和数组,「快速」求出「某⼀个区间内」所有元素的和: 当询问的区间是 [l, r] 时:区间内所有元素的和为: dp[r] - dp[l - 1] 。
代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNextInt()) { 
            int n = scan.nextInt();
            int q = scan.nextInt();
            int[] array = new int[n + 1];
            for(int i = 1; i <= n; i++) {
                array[i] = scan.nextInt();
            }
            // 使用long防止溢出
            long dp[] = new long[n + 1];
            dp[0] = 0; // 初始化
            for(int i = 1; i <= n; i++) {
                // 前缀和
                dp[i] = dp[i - 1] + array[i];
            }
            for(int i = 0; i < q; i++) {
                int l = scan.nextInt();
                int r = scan.nextInt();
                // 使用前缀和数组
                System.out.println(dp[r] - dp[l - 1]);
            }

        }
    }
}

【模板】二维前缀和

image.png

题目链接:【模板】二维前缀和

算法思路:

image.png

代码:
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        int q = scan.nextInt();
        int[][] array = new int[n+1][m+1];
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                array[i][j] = scan.nextInt();
            }
        }
        // 计算前缀和
        long[][] dp = new long[n+1][m+1];
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1] + array[i][j];
            }
        }
        while(q > 0) {
            int x1 = scan.nextInt();
            int y1 = scan.nextInt();
            int x2 = scan.nextInt();
            int y2 = scan.nextInt();
            // 使用前缀和
            System.out.println(dp[x2][y2] - dp[x2][y1 - 1] - dp[x1 - 1][y2] + dp[x1-1][y1-1]);
            q--;
        }
    }
}

寻找数组的中心下标

image.png

题目链接:寻找数组的中心下标

算法思路:

image.png

代码:
class Solution {
    public int pivotIndex(int[] nums) {
        int n = nums.length;
        int[] ldp = new int[n+1];
        int[] rdp = new int[n+1];
        // 计算左前缀和
        for(int i = 1; i < n; i++) {
            // ldp[i]计算的是[0,i-1]之和
            ldp[i] = ldp[i - 1] + nums[i - 1];
        }   
        // 计算右前缀和    
        for(int i = n - 2; i >= 0; i--) {
            // rdp[i]计算的是[i+1, n-1]之和
            rdp[i] = rdp[i+1] + nums[i+1];
        }
        for(int i = 0; i < n; i++) {
            if(ldp[i] == rdp[i]) {
                return i;
            }
        }
        return -1;
    }
}

除自身以外数组的乘积

image.png

题目链接:除自身以外数组的乘积

算法思路:

image.png

代码:
class Solution {
    public int[] productExceptSelf(int[] nums) {
        // 题目要求不能使用除法
        // 可以前缀积*后缀积
        int n = nums.length;
        int[] ldp = new int[n+1];
        int[] rdp = new int[n+1];
        // 乘数不能为0
        ldp[0] = 1;
        rdp[n-1] = 1;
        // 求前缀积
        for(int i = 1; i < n; i++) {
            // ldp[i]等于[0, i-1]之间的乘积
            ldp[i] = ldp[i-1] * nums[i-1];
        }
        // 求后缀积
        for(int i = n - 2; i >= 0; i--) {
            // rdp[i]等于[i+1, n-1]之间的乘积
            rdp[i] = rdp[i+1] * nums[i+1];
        }
        int[] answer = new int[n];
        for(int i = 0; i < n; i++) {
            answer[i] = ldp[i] * rdp[i];
        }
        return answer;
    }
}

和为K的子数组

image.png

题目链接:和为k的子数组

算法思路:

image.png

代码:
class Solution {
    public int subarraySum(int[] nums, int k) {
        // 我的第一个想法是滑动窗口,但是不行,因为数组中有0和负数,不具有单调性。
        // 我们可以考虑前缀和
        // 求该数组中和为 k 的子数组的个数,即求sum - k有几个
        // 所以可以引入哈希表,统计前缀和的个数
        Map<Integer, Integer> hashMap = new HashMap<>();
        // 如果整个前缀和为k时
        hashMap.put(0, 1);
        int sum = 0;// 用来统计当前位置的前缀和
        int result = 0; // 用来统计个数
        for(int x : nums) {
            sum += x;
            // 更新结果
            result += hashMap.getOrDefault(sum - k, 0);
            // 把当前前缀和加入哈希表
            hashMap.put(sum, hashMap.getOrDefault(sum, 0) + 1);
        }
        return result;
    }
}

和可被K整除的子数组

image.png

题目链接:和可被K整除的子数组

算法思路:

image.png
设 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 。因此,我们仅需⽤⼀个哈希表,⼀边求当前位置的前缀和,⼀边存下之前每⼀种前缀和出现的次数。
image.png

代码:
class Solution {
    public int subarraysDivByK(int[] nums, int k) {
        Map<Integer,Integer> hashMap = new HashMap<>();
        // 整个前缀和为0
        hashMap.put(0%k,1);
        int sum = 0; // 求前缀和
        int result = 0; 
        for(int x : nums) {
            sum += x; // 求当前位置的前缀和
            int r = (sum % k + k) % k; // 求余数
            // 更新结果
            result += hashMap.getOrDefault(r, 0);
            hashMap.put(r, hashMap.getOrDefault(r, 0) + 1);
        }
        return result;
    }
}

连续数组

image.png

题目链接:连续数组

算法思想:

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

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

image.png

代码:
class Solution {
    public int findMaxLength(int[] nums) {
        // 将0换成-1,即求和为0的最长连续子数组
        int n = nums.length;
        for(int i = 0; i < n; i++) {
            if(nums[i] == 0) {
                nums[i] = -1;
            }
        }
        Map<Integer, Integer> hash = new HashMap<>();
        hash.put(0, -1); // 前缀和为0
        int sum = 0;
        int result = 0;
        for(int i = 0; i < n; i++) {
            sum += nums[i];
            if(hash.containsKey(sum)) {
                 result = Math.max(result, i - hash.get(sum));
            }else {
                // 第一次出现
                hash.put(sum, i);
            }

        }
        return result;
    }
}

矩阵区域和

image.png

题目链接:https://leetcode.cn/problems/matrix-block-sum/

算法思路:

image.png⼆维前缀和的简单应⽤题,关键就是我们在填写结果矩阵的时候,要找到原矩阵对应区域的「左上⻆」以及「右下⻆」的坐标(推荐⼤家画图)左上⻆坐标: 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;
        // 求二维前缀和
        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];
            }
        }
        // 使用二维前缀和
        int[][] answer = 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, y1 = Math.max(0, j - k) +1;
                int x2 = Math.min(m-1, i + k) + 1, y2 = Math.min(n-1, j + k) + 1;
                answer[i][j] = dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1];
            }
        }
        return answer;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker安装etherpad文档系统

效果 安装 1.创建并进入目录 mkdir -p /opt/etherpad cd /opt/etherpad 2.修改目录权限 chmod -R 777 /opt/etherpad 3.创建并启动容器 docker run -d --name etherpad --restart always -p 10054:9001 -v /opt/etherpad/data:/opt/etherpad-lite/var etherpad/etherpad:la…

YOLO-World——超级轻量级开放词汇目标检测方法

前言 目标检测一直是计算机视觉领域中不可忽视的基础挑战&#xff0c;对图像理解、机器人技术和自主驾驶等领域具有广泛应用。随着深度神经网络的发展&#xff0c;目标检测方面的研究取得了显著进展。尽管这些方法取得了成功&#xff0c;但它们存在一些限制&#xff0c;主要体…

业务架构设计之汽配供应链与实现的实践总结

随着汽车行业的不断发展&#xff0c;汽配供应链的规模和复杂度也在不断增加。为了满足市场需求&#xff0c;建立一个高效、可靠的汽配供应链业务系统至关重要。本文将总结一些关键的实践经验&#xff0c;帮助读者了解如何设计和实现一个稳定且高效的汽配供应链业务系统。 1. 业…

从零开始手写mmo游戏从框架到爆炸(七)— 消息封装

上一篇&#xff0c;我们初步把消息handler 注册到了服务中&#xff0c;在进行后续工作之前我们需要再做一些准备工作。 第一&#xff1a;把之前自己管理的bean放到spring中去管理&#xff0c;后面大部分的bean都通过spring来管理。 第二&#xff1a;为了方便路由消费&#xff0…

C语言:内存函数

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; C语言标准库中有这样一些内存函数&#xff0c;让我们一起学习吧&#xff01;&#xff01; 一、memcpy函数的使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); 1.1 使…

分享65个节日PPT,总有一款适合您

分享65个节日PPT&#xff0c;总有一款适合您 65个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1hc1M5gfYK8eDxQVsK8O9xQ?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知…

编译原理与技术(二)——词法分析(一)正则表达式

一、词法分析的概貌 一个程序&#xff0c;在我们看来往往是像下图这样的。 实际上&#xff0c;上面的程序本质上就是一个字符串&#xff0c;所以&#xff0c;它等价于下面这样的。 上面的字符串&#xff08;字符流&#xff09; &#xff0c;就是编译器接收到的程序的形式。 所…

centos安装inpanel

前置条件 安装python yum -y install python 安装 cd /usr/local git clone https://gitee.com/WangZhe168_admin/inpanel.git cd inpanel python install.py 安装过程需要设置账户 密码 端口号 我设置的是admin:admin 10050 使用 打开浏览器,输入 http://192.168.168.…

【人工智能】神奇的Embedding:文本变向量,大语言模型智慧密码解析(10)

什么是嵌入&#xff1f; OpenAI 的文本嵌入衡量文本字符串的相关性。嵌入通常用于&#xff1a; Search 搜索&#xff08;结果按与查询字符串的相关性排序&#xff09;Clustering 聚类&#xff08;文本字符串按相似性分组&#xff09;Recommendations 推荐&#xff08;推荐具有…

02.05

1.单链表 main #include "1list_head.h" int main(int argc, const char *argv[]) { //创建链表之前链表为空Linklist headNULL;int n;datatype element;printf("please enter n:");scanf("%d",&n);for(int i0;i<n;i){printf("ple…

22.仿简道云公式函数实战-数学函数-COT

1. COT函数 COT 函数可用于计算角度的余切值。 2. 函数用法 COT(弧度) 使用该函数时&#xff0c;需要将角度转化为弧度参与计算&#xff0c;可通过 RADIANS 函数 将角度转化为弧度。 3. 函数示例 如计算 COT(45) 的值&#xff0c;可设置公式为COT(RADIANS(45))&#xff0…

算法——二分查找算法

1. 二分算法是什么&#xff1f; 简单来说&#xff0c;"二分"指的是将查找的区间一分为二&#xff0c;通过比较目标值与中间元素的大小关系&#xff0c;确定目标值可能在哪一半区间内&#xff0c;从而缩小查找范围。这个过程不断重复&#xff0c;每次都将当前区间二分…

算法练习-四数之和(思路+流程图+代码)

难度参考 难度&#xff1a;中等 分类&#xff1a;数组 难度与分类由我所参与的培训课程提供&#xff0c;但需要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0c;旨在…

配置git环境与项目创建

项目设计 名称&#xff1a;KOB 项目包含的模块 PK模块&#xff1a;匹配界面&#xff08;微服务&#xff09;、实况直播界面&#xff08;WebSocket协议&#xff09; 对局列表模块&#xff1a;对局列表界面、对局录像界面 排行榜模块&#xff1a;Bot排行榜界面 用户中心模块&…

【Qt】常见问题

1.存在未解析的标识符 将build文件夹删掉重新编译。 2.左侧项目目录栏无法删除已添加项目 打开目标项目上一级的pro文件&#xff0c;将目标文件名字注释或者删除掉&#xff0c;最后保存&#xff0c;qt就会自动更新&#xff0c;将该项目隐藏掉。 3.在qt creator下添加槽函数…

大型装备制造企业案例分享——通过CRM系统管理全球业务

本期&#xff0c;小Z为大家带来的CRM管理系统客户案例是某大型装备制造企业运用Zoho CRM管理全球业务的过程分享。该企业是创业板上市公司&#xff0c;业务遍及100多个国家和地区&#xff0c;合作伙伴超百位&#xff0c;拥有覆盖全球的销售和服务网络。截止目前&#xff0c;相继…

油猴js 获取替换网页链接并重定向

场景 适用一些镜像网站进行重定向&#xff0c;比如Github。 代码 // UserScript // name New Userscript // namespace http://tampermonkey.net/ // version 2024-02-06 // description try to take over the world! // author You // match …

❤ React18 环境搭建项目与运行(地址已经放Gitee开源)

❤ React项目搭建与运行 环境介绍 node v20.11.0 react 18.2 react-dom 18.2.0一、React环境搭建 第一种普通cra搭建 1、检查本地环境 node版本 18.17.0 检查node和npm环境 node -v npm -v 2、安装yarn npm install -g yarn yarn --version 3、创建一个新的React项目…

OpenCV 图像处理六(傅里叶变换、模板匹配与霍夫变换)

文章目录 一、傅里叶变换1.1 NumPy实现和逆实现1.1.1 NumPy实现傅里叶变换Demo 1.1.2 NumPy实现逆傅里叶变换Demo 1.2 OpenCV实现和逆实现1.2.1 OpenCV实现傅里叶变换Demo 1.2.2 OpenCV实现逆傅里叶变换Demo 1.3 频域滤波1.3.1低频、高频1.3.2 高通滤波器构造高通滤波器Demo 1.…

jquery写表格,通过后端传值,并合并单元格

<!DOCTYPE html> <html> <head><title>Table Using jQuery</title><style>#tableWrapper {width: 100%;height: 200px; /* 设置表格容器的高度 */overflow: auto; /* 添加滚动条 */margin-top: -10px; /* 负的外边距值&#xff0c;根据实际…