前缀和算法——优选算法

news2024/10/11 13:40:07

个人主页:敲上瘾-CSDN博客

个人专栏:游戏、数据结构、c语言基础、c++学习、算法

一、什么是前缀和?

        前缀和是指从数组的起始位置到某一位置(或矩阵的某个区域)的所有元素的和。这种算法通过预处理数组或矩阵,计算出每个位置(或区域)的前缀和,并将其存储在一个额外的数组或矩阵中,以便在后续查询中可以快速获取任意区间(或区域)的和。

        对于一维数组,可以使用递推公式dp[i] = dp[i - 1] + arr[i]来计算前缀和;对于二维矩阵,可以使用类似的递推公式,但需要考虑更多的边界情况。接下来我会用两个题来详细讲解前缀和的使用。

二、一维前缀和

和为k的子数组

        暴力解法: 分别以下标为0,1,... ,nums.size()-1为子数组的左边界依次往右延伸生成子数组。每次延伸需要判断子数组和是否为k。时间复杂度为O(N^2)代码如下:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k)
    {
        int ret=0;
        for(int i=0;i<nums.size();i++)
        {
            int sum=0;
            for(int j=i;j<nums.size();j++)
            {
                sum+=nums[j];
                if(sum==k) ret++;
            }
        }
        return ret;
    }
};

前缀和算法:

        如图要使子数组v的和等于目标值k则一定有sum2-sum1=k,即有sum1=sum2-k。那么我们可以计算一下该数组元素的前缀和并在计算过程中进行满足条件的子数组进行记录。注意这里是需要在计算前缀和的过程中进行统计,而不是完成所有前缀和计算后统计。记i=0,我们从下标i往右依次遍历。

需要考虑一下下面几个细节:

  • 因为这里需要往前查找前缀和所以为了提高效率,我们把i位置的前缀和结果累计在一个哈希表中,即unordered_map<int,int>它表示是<前缀和w,前缀和w出现的次数>。
  • 需要在元素存入哈希表之前进行统计目标子数组个数,也就是从左往右依次计算前缀和然后进行统计,最后才把该前缀和放入哈希表。这样可以不重不漏的完成计数。
  • 不需要单独再创建数组来储存前缀和,但是考虑要方便的记录i位置的前缀和,需要一个变量来储存前一个元素(即i-1)的前缀和。
  • 初始化:如果i位置的前缀和恰好为k,即sum2-k等于0,说明该位置到下标为0的这块区间都是满足条件的,是需要记录的,但是在它前面并没有一个位置的下标前缀和为0,所以需要将哈希表的前缀和为0的位置初始化为一次。
class Solution {
public:
    int subarraySum(vector<int>& nums, int k)
    {
        unordered_map<int,int> hash;
        hash[0]=1;//初始化哈希表
        int result=0;
        int sum=0;//计算前缀和
        for(int i=0;i<nums.size();i++)
        {
            sum+=nums[i];
            if(hash.count(sum-k))//如果hash表中有sum-k这个元素
                result+=hash[sum-k];
            //i位置的前缀和累计到哈希表中
            hash[sum]++;
        }
        return result;
    }
};

三、二维前缀和 

矩阵区域和

题目的意思是给你一个mat矩阵和,你需要返回的是一个同等规模的矩阵answer

其中矩阵answer[i][j]记录的是mat矩阵中(i,j)位置往四面八方延伸k个元素得到的子矩阵的和。

如下mat矩阵中不同的(i,j)位置,不同的k延伸得到的矩阵。

        这个题如果用暴力解法的话时间复杂度非常地高,而且有大量的重复计算,因为有重复计算所以可以往前缀和方面考虑。

首先我们可以额外开辟同规模的二维空间,记为dp,使用dp来储存从(i,j)到(0,0)位置为对角围成的矩阵的前缀和。

        如上(i,j)位置的前缀和dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+mat[i][j]。我们使用两层for循环就可以将所有位置的前缀和填到dp表中。

那么我们如何使用前缀和数组呢?我们来看下面面积A的计算。

        一块随机的面积若不考虑边界问题我们都可以把它分成四块已知前缀和的小矩阵。如上分解A=S1-S2-S3+S4,而这些面积已经储存在dp表中我们只需要找到它们的下标就能在dp表中找到。所以现在关键的是确定它们的下标位置,如下:

A=dp[x2][y2]-dp[x1][y2]-dp[x2][y1]+dp[x1][y1]。

对于一个m*n大小的矩阵的下标的查找:

x1=i-k,y1=j-k。边界处理:如果x1<0则dp[x1][y1]和dp[x1][y2]不用参与计算当做0处理。

x2=i+k,y2=j+k。边界处理:若x2>=m,则改为x2=m-1,若y2>=n则改为y2=n-1。

接下来我们就需要再开辟一块空间来储存结果,使用两个for循环将每个位置按公式

                dp[i][j]=dp[x2][y2]-dp[x1][y2]-dp[x2][y1]+dp[x1][y1]

计算,但要考虑边界情况,最后返回该矩阵即可。

class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k)
    {
        int m=mat.size(),n=mat[0].size();
        //dp表的创建
        vector<vector<int>> dp(mat.size(),vector<int>(mat[0].size(),0)); 
        for(int i=0;i<dp.size();i++)
        {
            for(int j=0;j<dp[0].size();j++)
            {
                int s1=0,s2=0,s3=0;
                if(i-1>=0) s1=dp[i-1][j];
                if(j-1>=0) s2=dp[i][j-1];
                if(i-1>=0&&j-1>=0) s3=dp[i-1][j-1];
                dp[i][j]=s1+s2-s3+mat[i][j];
            }
        }
        //dp表的使用
        vector<vector<int>> ret(m,vector<int>(n,0)); 
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                int s1=0,s2=0,s3=0,s4=0;//初始化面积
                //坐标计算
                int x1=i-k,y1=j-k,x2=i+k,y2=j+k;
                if(x2>=m) x2=m-1;
                if(y2>=n) y2=n-1;
                //面积计算
                s1=dp[x2][y2];
                if(x1>=0) s2=dp[x1][y2];
                if(y1>=0) s3=dp[x2][y1];
                if(x1>=0&&y1>=0) s4=dp[x1][y1];
                ret[i][j]=s1-s2-s2+s4;
            }
        }
        return ret;
    }
};

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

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

相关文章

[Git] 演示回退命令reset的三种模式soft、hard、mixed详解

前言 目录 git reset soft hard mixed git reset --soft commitId git reset --hard commitId git reset --mixed commitId git reset soft 移动本地库HEAD指针 hard 移动本地库HEAD指针 重置暂存区 重置工作区 mixed 移动本地库HEAD指针重置暂存区 执行reset命令后…

秒杀|基于springBoot的秒杀系统设计与实现(附项目源码+论文+数据库)

私信或留言即免费送开题报告和任务书&#xff08;可指定任意题目&#xff09; 摘要 社会发展日新月异&#xff0c;用计算机应用实现数据管理功能已经算是很完善的了&#xff0c;但是随着移动互联网的到来&#xff0c;处理信息不再受制于地理位置的限制&#xff0c;处理信息及…

游戏行业八大趋势解说(上)

今天&#xff0c;来看看游戏行业八大趋势~ 1. 跨平台发行 2. 单人游戏规模缩小 3. 移动应用生态系统开放 4. 社区管理、抢先体验成为主流 5. 免费游戏的时间占有率显著提高 6. 新AAA游戏面临挑战 7. 生成式AI的影响未完全显现 8. 新世代成为主流&#xff0c;用户生成内…

35岁零基础能转型AI大模型吗?来得及不?

以下从3个方面帮大家分析&#xff1a; 35岁转行会不会太晚&#xff1f;零基础学习AI大模型开发能不能学会&#xff1f;AI大模型开发行业前景如何&#xff0c;学完后能不能找到好工作&#xff1f; 一、35岁转行会不会太晚&#xff1f; 35岁正处于人生的黄金时期&#xff0c;拥…

VMWare vsphere ESXi 6.7在线升级至7.0.3

本文记录了VMWare vsphere ESXi 6.7在线升级至7.0.3的过程 一、当前环境 1、ESXi当前版本&#xff1a;6.7.0, 17499825 2、VCenter当前版本&#xff1a;7.0.3 二、导入升级包并新建基准 1、新版本ISO信息 VMware-VMvisor-Installer-7.0U3n-21930508.x86_64.iso【MD5SUM: 0c…

Python酷库之旅-第三方库Pandas(143)

目录 一、用法精讲 646、pandas.Timestamp.is_quarter_start属性 646-1、语法 646-2、参数 646-3、功能 646-4、返回值 646-5、说明 646-6、用法 646-6-1、数据准备 646-6-2、代码示例 646-6-3、结果输出 647、pandas.Timestamp.is_year_end属性 647-1、语法 647…

马斯克的Cybercab首秀!没有方向盘和踏板,26年量产,特斯拉这次又玩大的了

家人们&#xff01;今天是特斯卡开“We Robot”发布会的日子&#xff0c;从早上十点奶茶就搬一个小板凳蹲着了&#xff01; 这次发布会公开了没有方向盘、没有倒车镜、没有踏板制动器的自动驾驶出租车和Optimus机器人的最新进展&#xff0c;还是很震撼的&#xff5e;奶茶带大家…

Spring Boot 应用开发:入门与实战

Spring Boot 应用开发&#xff1a;入门与实战 引言 Spring Boot 是 Spring 框架的一个子项目&#xff0c;旨在简化 Spring 应用的配置和开发。它通过自动配置和嵌入式服务器&#xff0c;极大地简化了 Java 企业级应用的开发。本文将详细介绍 Spring Boot 的核心概念&#xff…

linux 搭建sentinel

1.下载 linux执行下面的命令下载包 wget https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar2.启动 nohup java -Dserver.port9090 -Dcsp.sentinel.dashboard.serverlocalhost:9090 -Dproject.namesentinel-dashboard -jar sentin…

Docker镜像制作实战实现淘宝网站部署

登录docker环境nohup /usr/local/docker/dockerd -H 0.0.0.0:2375 -H unix:///var/run/docker.sock & 创建仓库源&#xff0c;上传daemon.json&#xff0c;内容为镜像仓库地址 重启docker服务&#xff0c;加载镜像源 下载nginx镜像 也可通过已知镜像地址下载命令如下 下载…

数据结构_day1

目录 大纲 1.数据结构基础知识 1.1 什么是数据结构 1.2 数据 1.3 逻辑结构 1.4 存储结构 1.4.1 顺序存储 1.4.2 链式存储 1.4.3 索引存储结构 1.4.4 散列存储 1.5 操作 2.算法基础知识 2.1 什么是算法 2.2 算法的设计 2.3 算法的特性 2.4 评价算法的好坏 大纲 数据结构、算法(理…

AI绘画ComfyUI 也可以有插件市场!

前言 上文我们介绍了 ComfyUI 的本地部署和基本使用。其中的插件安装&#xff0c;小伙伴们是不是觉得还是有点麻烦的&#xff0c;ComfyUI 有没有类似 WebUI 的插件管理功能呢&#xff0c;其实是有的&#xff0c;而且比 WebUI 的插件管理功能更强大。 今天我们就主要来介绍一下…

【目标检测】常见机械零件数据集5900张5类VOC+YOLO

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;5913 标注数量(xml文件个数)&#xff1a;5913 标注数量(txt文件个数)&#xff1a;5913 标注…

大数据面试-笔试SQL

一个表table: c_id u_id score&#xff1b;用SQL计算每个班级top5学生的平均分&#xff08;腾讯&#xff09; select class_id,avg(score) as score_avg from (select *,row_number() over(partition by class_id order by score desc) as score_rank from table ) t1 where t…

<<迷雾>> 第10章 用机器做一连串的加法(7)--装载数据的过程及相加过程 示例电路

info::操作说明 此电路属于将前述电路的 控制器 部分单独独立出来. 操作过程与前述类似, 参考前一个示例的操作步骤. primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/cyjsjdmw-examples/assets/circuit/cyjsjdmw-ch10-11-process…

electron-vite_4使用WebContentsView快速集成已有项目

Web 嵌入官方推荐使用WebContentsView&#xff1b;集成也比较简单&#xff0c;但还是需要你单独写点东西&#xff1b; src/main/index.ts进行修改 import { app, shell, BrowserWindow, ipcMain, nativeImage, WebContentsView, dialog } from electron;function createWindo…

吹爆这份Stable diffusion提示词攻略(含链接)

Stable diffusion 提示词里面的各种符号小括号 ( )、大括号 { }、中括号 [ ]、尖括号<>、竖线|、下划线_到底是什么意思&#xff1f; ** ** 别担心&#xff0c;这篇文章三分钟教会你填写 Stable diffusion 提示词的各种烦恼~~ SD提示词基础&#xff1a; 1、提示词与提…

【算法】——双指针算法合集(力扣)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 第一题&#xff1a;移动零 第二题&#xff1a;复写零 第三题&#xff1a;快乐数 第四题&#xff1a…

鸿蒙学习笔记--搭建开发环境及Hello World

文章目录 一、概述二、开发工具下载安装2.1 下载开发工具DevEco Studio NEXT2.2 安装DevEco Studio 三、启动软件四、第一个应用Hello World4.1 创建应用4.2 创建模拟器4.3 开启Hyper-v功能4.4 启动虚拟机 剑子仙迹 诗号&#xff1a;何须剑道争锋&#xff1f;千人指&#xff0c…

免费又好用的保护网站WAF,基于语义引擎的waf雷池社区版推荐

为什么传统规则防护失效了&#xff1f;&#x1f914; 目前&#xff0c;大多数 Web 应用防火墙&#xff08;WAF&#xff09;依赖规则匹配来识别和阻断攻击流量。然而&#xff0c;随着 Web 攻击的低成本、复杂多样的手段和频繁爆发的高危漏洞&#xff0c;管理人员不得不频繁调整防…