【C++ 算法进阶】算法提升四
数组查询问题 (数组优化)
题目
数组为 {3 , 2, 2 ,3 ,1} 查询为(0 ,3 ,2)
这个查询的意义是 在数组下标0~3这个范围上 有多少个2 (答案为2)
假设现在给你一个数组arr 假设我们对于这个数组的查询十分频繁
现在要求你返回所有的查询结果
题目分析
我们可以看到题目中有 对于这个数组的查询十分频繁 这句描述
看到之后我们自然就可以想到我们要做一个预处理数组来让查询的代价尽可能的低 (现在的代价是O(M)) M为查询数组的长度
这里提供两个预处理数组的思路
- 因为每次给的范围是随机的 所以说我们从数字入手 对于每个数字建立一张下标表 以后每次查询的时候只需要通过二分法找到范围内数字的下标即可 这样我们的时间复杂度就成为了二分法的时间复杂度
- 我们可以从数字的范围开始入手 对于每个数字统计它在0~N范围上出现的次数 以后假设我们需要求从 J到K上某个数字出现的次数就只需要让这个数组的K位置的数字减去J位置的数字即可 这样的时间复杂度就是O(1)了
我们这里提供方法二的解
代码解析
这里需要注意的是
for (auto& it : map)
上面这一行代码 如果我们没有写& 那么他就是值遍历 导致我们下面的修改没有事实上修改map数组内的数据
int main() {vector<int> arr = {3 ,2 ,2 , 3, 1};// 这里建立N个数组 每个数组和arr一样长 代表从0开始到当前位置有多少个当前数unordered_map<int, vector<int>> map;for (auto x : arr){if (map.count(x) == 0){map[x] = vector<int>(arr.size(), 0);}}// 开始填表 for (auto& it : map){int count = 0;for (int i = 0; i < arr.size(); i++){if (it.first == arr[i]){count++;}it.second[i] = count;}}cout << map[2][3] - map[2][1] << endl;return 0;
}
子数组的最大累加和 (经典动态规划)
题目
本题为LC原题 题目如下
题目分析
这是一道最经典的动态规划问题 是一个以i为结尾位置的模型
我们只需要使用一个dp数组 记录下从0开始的每个位置为结尾时 能够获取的最大值是多少即可
因为子数组的结尾肯定是在原数组中的 所以说我们计算每个位置作为结尾的最大和肯定能算出最终答案
代码解析
本题没有什么难点
class Solution {
public:int maxSubArray(vector<int>& nums) {if (nums.size() == 1) {return nums[0];}// 首先创建一个dp数组vector<int> dp(nums.size() , 0);dp[0] = nums[0];for (int i = 1 ; i < nums.size(); i++) {dp[i] = dp[i-1] < 0 ? nums[i] : dp[i-1] + nums[i];}int max = dp[0];for (auto x : dp) {if (x >max) {max = x;}}return max;}
};
二维数组 子矩阵的最大累加和 (数组压缩 + 动态规划)
题目
返回一个二维数组中 子矩阵的最大累加和 此题为LC原题 题目如下
题目分析
这道题其实就是我们第二题的变种
思路相同 : 如果我们要求一个子矩阵和的最大值 那么我们可以将问题转化成
求以每一行作为矩阵的头 往下扩展时 矩阵的最大值
因为矩阵肯定在二维数组内 所以说只要我们求出以每一行作为起始的最大值 就能求出最终的答案
数组压缩技巧
当我们求第一行时 我们可以直接照搬上一题的代码
当我们求第一行到第N行时 因为我们求的是和 所以说我们可以将各列的代码相加 组成一个新的数组 再使用第一行的技巧
代码详解
class Solution {
public:vector<int> getMaxMatrix(vector<vector<int>>& matrix) {int N = matrix.size();int M = matrix[0].size(); int a = 0;int begin = 0;int c = 0;int d = 0;int max = INT_MIN;for (int i = 0; i < N; i++) {vector<int> arr(M , 0);for (int j = i; j < N;j++) {int cur = 0;int b = 0; // 这个值要变化for (int k = 0; k < M; k++) {arr[k] += matrix[j][k];cur += arr[k];if (cur > max) {max = cur;a = i;begin = b;c = j;d = k;}if (cur < 0) {cur = 0;b = k + 1;}}}}return {a , begin, c, d};}
};
子序列的最大累加和 (动态规划)
题目
返回一个数组中 选择的数字不能相邻的情况下 最大子序列的累加和
题目分析
这里提供给大家一个思路 只要我们看到 子序列
这几个字 我们就要想到这是一种从左到右的尝试模型
我们可以定义一个函数 int process(vector<int>& arr, int index, vector<int>& memo)
该函数能否返回在index位置的时候子序列的最大累加和
那么接下来我们就只需要列出边界和各种的可能性即可
代码详解
#include<iostream>
using namespace std;
#include<vector>int process(vector<int>& arr, int index, vector<int>& memo) {if (index >= arr.size()) {return 0;}// 如果已经计算过,直接返回if (memo[index] != -1) {return memo[index];}// 选择当前数字并跳过下一个数字int p1 = arr[index] + process(arr, index + 2, memo);// 不选择当前数字int p2 = process(arr, index + 1, memo);// 记录结果memo[index] = max(p1, p2);return memo[index];
}int getMaxSumNonAdjacent(vector<int>& arr) {if (arr.empty()) {return 0;}vector<int> memo(arr.size(), -1); // 用于记忆化的数组return process(arr, 0, memo);
}
糖果问题 (贪心)
题目
本题为LC原题 题目如下
题目分析
这个问题是一种贪心问题
相邻的两个孩子评分更高的孩子会获得更多的糖果
- 左规则:当 ratings[i−1]<ratings[i] 时 i 号学生的糖果数量将比 i−1 号孩子的糖果数量多
- 右规则:当 ratings[i]>ratings[i+1] 时 i 号学生的糖果数量将比 i+1 号孩子的糖果数量多
所以说我们可以将这个数组遍历两次
- 从左到右遍历 遇到比前一个位置大的糖果就++ 否则糖果归1
- 从右到左遍历 遇到比前一个位置大的糖果就++ 否则糖果归1
之后我们将这两次遍历的结果取较大值即可 (因为要同时满足这两个条件)
代码详解
class Solution {
public:int candy(vector<int>& ratings) {int M = ratings.size();vector<int> left(M , 0);vector<int> right(M , 0);left[0] = 1;for (int i = 1 ; i < M; i++) {if (ratings[i] > ratings[i-1]) {left[i] = left[i-1] + 1;} else {left[i] = 1;}}right[M - 1] = 1;for (int i = M - 2; i >=0 ; i--) {if (ratings[i] > ratings[i+1]) {right[i] = right[i+1] + 1;} else {right[i] = 1;}}for (int i = 0; i < M; i++) {left[i] = left[i] > right[i] ? left[i] :right[i];}int max = 0;for (auto x : left) {max += x;}return max;}
};
生成数组(分治)
题目
给定一个正数为size 生成长度为size的达标数组
达标: 对于任意的 i < k < j 满足 [I] + [J] != 2*[K]
题目分析
这是一道典型的分治问题 想到这种思路的过程挺难的 这里直接提供思路
假设一个数组达标 那么这个数组的两倍肯定也达标 这个数组的两倍+1肯定也达标 (自己使用公式验证下就能明白)
那么数组的两倍 再加上这个数组的两倍+1 组成的一个新数组 肯定也达标
这是为什么呢?
因为我们如果从这个数组的左边或者右边任意选一个数相加 那么他们相加肯定是奇数 而最后要达标则要是偶数2*[K]
所以说我们可以从一个数开始 二倍二倍的往上扩 自然就能求出最终答案
如果不是2的n次方怎么办呢?
只需要舍弃掉后面多余的数字即可
代码详解
vector<int> process(int size) {if (size == 1) {return { 1 };}int halfsize = (size + 1) / 2;vector<int> half = process(halfsize);// 构造出一个完成的数组// 一半是奇数 一半是偶数vector<int> ans;for (int i = 0; i < halfsize; i++) {ans.push_back(half[i] * 2 + 1);}for (int i = halfsize; i < size; i++) {ans.push_back(half[i - halfsize] * 2);}return ans;
}int main() {vector<int> ans = process(9);for (auto x : ans) {cout << x << endl;}return 0;
}
字符串交错组成 (动态规划 – 样本对应模型)
题目
此题为LC原题目 题目如下
题目分析
遇到这种多个字符串问题 我们第一时间想到的就是要用动态规划的样本对应模型去解决
首先设置一个process函数
bool process(string& s , string& s1 , string&s2 , int index1 , int index2)
这个函数的含义是 从s1的第index1个位置 s2的第index2个位置开始 能否组成字符串s
之后我们只需要考虑三种情况
- 终止条件
- 越界情况
- 有几种可能性
代码详解
class Solution {
public:// 带有记忆化搜索的递归函数bool process(string& s1, string& s2, string& s3, int index1, int index2, vector<vector<int>>& dp) {// 如果 s1 和 s2 的字符都处理完了,且正好匹配了 s3 的长度if (index1 == s1.size() && index2 == s2.size()) {return true;}// 检查越界情况if (index1 > s1.size() || index2 > s2.size()) {return false;}// 如果 dp 中已经计算过该状态,直接返回存储的结果if (dp[index1][index2] != -1) {return dp[index1][index2];}// 当前字符在 s3 中的位置int sIndex = index1 + index2;// 尝试从 s1 中取字符bool p1 = false;if (index1 < s1.size() && s1[index1] == s3[sIndex]) {p1 = process(s1, s2, s3, index1 + 1, index2, dp);}// 尝试从 s2 中取字符bool p2 = false;if (index2 < s2.size() && s2[index2] == s3[sIndex]) {p2 = process(s1, s2, s3, index1, index2 + 1, dp);}// 存储结果:如果 p1 或 p2 为 true,存储 1;否则存储 0dp[index1][index2] = (p1 || p2);return dp[index1][index2];}// 主函数入口bool isInterleave(string s1, string s2, string s3) {// 边界条件检查:如果 s3 的长度不等于 s1 和 s2 长度之和,返回 falseif (s3.size() != s1.size() + s2.size()) {return false;}// 初始化 dp 数组,值全为 -1,表示尚未计算vector<vector<int>> dp(s1.size() + 1, vector<int>(s2.size() + 1, -1));// 从 index1 = 0, index2 = 0 开始return process(s1, s2, s3, 0, 0, dp);}
};
大楼轮廓线问题 ()
相关文章:

【C++ 算法进阶】算法提升四
数组查询问题 (数组优化) 题目 数组为 {3 , 2, 2 ,3 ,1} 查询为(0 ,3 ,2) 这个查询的意义是 在数组下标0~3这个范围上 有多少个2 (答案为2&…...

多种方式实现安全帽佩戴检测
为什么要佩戴安全帽 在探讨安全帽佩戴检测之前,我们先来了解下安全帽佩戴的必要性: 保护头部免受外力伤害 防止物体打击 在建筑施工、矿山开采、工厂车间等场所,经常会有高空坠物的风险。例如在建筑工地上,可能会有工具、材料、…...

基于PHP+MySQL+Vue的网上订餐系统
摘要 本文介绍了一个基于PHPMySQLVue技术的网上订餐系统。该系统旨在为用户提供便捷的在线订餐服务,同时提高餐厅的运营效率。系统后端采用PHP语言开发,利用MySQL数据库进行数据存储与管理,实现了用户注册登录、菜品浏览、购物车管理、订单提…...

Vue学习笔记 Class绑定 Style绑定 侦听器 表单输入绑定 模板引用 组件组成 组件嵌套关系
文章目录 Class绑定绑定对象绑定数组注意事项 style绑定绑定对象代码效果展示 绑定数组 侦听器注意的点代码效果 表单输入绑定示例代码效果展示 修饰符.lazy.number.trim 模板引用组件组成组件组成结构引入组件步骤style中的scoped作用 组件嵌套关系 Class绑定 绑定对象 绑定数…...

【AIGC】ChatGPT与人类理解力的共鸣:人机交互中的心智理论(ToM)探索
博客主页: [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯心智理论(Theory of Mind,ToM)心智理论在心理学与神经科学中的重要性心智理论对理解同理心、道德判断和社交技能的重要性结论 💯乌得勒支大学研究对ChatGPT-4…...

代码训练营 day39|0-1背包问题,LeetCode 416
前言 这里记录一下陈菜菜的刷题记录,主要应对25秋招、春招 个人背景 211CS本CUHK计算机相关硕,一年车企软件开发经验 代码能力:有待提高 常用语言:C 系列文章目录 第九章 动态规划part03 文章目录 前言系列文章目录第九章 动态…...

LeetCode 203 - 移除链表元素
题目描述 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点,并返回 新的头节点 。 解题思路 创建一个虚拟头节点dummyHead,并将其next指向给定的头节点head,这样可以避免处理头节点的特…...

【海图界面上一些常见术语UTC、HDG、COG、SOG、LAT、LON的基本解释】
当然,以下是关于海图界面上一些常见术语UTC、HDG、COG、SOG、LAT、LON的基本解释: UTC (Coordinated Universal Time) 定义:UTC 是协调世界时(Coordinated Universal Time)的缩写,是一种与地球自转无关的…...

HL7协议简介及其在STM32上的解析实现
近期完成一个医疗相关的项目,其中包括了体征监测设备,该设备使用的通信协议便是HL7 V2.4 协议,在医疗信息化领域,HL7(Health Level Seven)协议扮演着至关重要的角色。它是一种国际标准,用于定义医疗机构间以及医疗设备与信息系统之间的数据交换格式和通信协议。HL7标准旨…...

TensorRT推理端到端
TensorRT推理端到端 1.参考链接2.宿主机上安装CUDA 12.4.13.安装nvidia-container-toolkit4.创建ghcr.io/intel/llvm/ubuntu2204_base容器5.容器内安装CUDA 12.4.1 + TensorRT10.1.06.安装依赖7.准备resnet50模型8.准备bert模型9.准备yolov5m模型10.编译TensorRT推理程序11.onn…...

获取历史的天气预报数据的网站
要获取从2019年到现在某个中国城市的天气数据,您可以通过以下方法实现: 1. 使用第三方天气数据API 许多天气服务提供商提供了历史天气数据的API接口,您可以通过这些API获取所需的数据。以下是一些常用的天气数据API提供商: 1.1…...

【VUE】Vue中常用的修饰符
事件修饰符 .stop:阻止事件冒泡。.prevent:阻止默认事件。.capture:使用事件捕获模式。.self:只当事件在该元素本身(比如不是子元素)触发时触发回调。.once:只触发一次事件。 按键修饰符 .en…...

数据分箱:如何确定分箱的最优数量?
选择最优分箱可以考虑以下几种方法: 一、基于业务理解 分析业务背景:从业务角度出发,某些特征可能有自然的分组或区间划分。例如,年龄可以根据不同的人生阶段进行分箱,收入可以根据常见的收入等级划分。 优点&#x…...

机器学习核心功能:分类、回归、聚类与降维
机器学习核心功能:分类、回归、聚类与降维 机器学习领域的基本功能类型通常按照学习模式、预测目标和算法适用性来分类。这些类型包括监督学习、无监督学习、半监督学习和强化学习,它们可以进一步细化为特定的任务,如分类、回归、聚类和降维…...

Python爬虫-eBay商品排名数据
前言 本文是该专栏的第39篇,后面会持续分享python爬虫干货知识,记得关注。 本文以eBay为例,通过搜索目标”关键词“,获取相关搜索”关键词“的商品排名数据。废话不多说,具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。接下来,跟着笔者直接往下看正文详…...

LabVIEW提高开发效率技巧----图像处理加速
在现代工业和科研中,图像处理技术被广泛应用于质量检测、自动化控制、机器人导航等领域。然而,随着图像数据量的增加,传统的CPU处理方式可能难以满足实时性和高效处理的需求。LabVIEW通过结合NI Vision模块和FPGA硬件平台,可以显著…...

AcWing1027
题目重述: 题目的核心是找到一条路径的最大权值总和,但路径要从起点 (1, 1) 走到终点 (n, n)。由于两条路径分别经过不同的格子,我们可以巧妙地将问题简化为两次同时出发的路径问题。这种映射的设计让我们能够更方便地处理两条路径重叠在同一…...

23 Shell Script服务脚本
Linux 服务脚本 一、Linux 开机自动启动服务 linux开机服务原理: ①linux系统启动首先加载kernel ②初始操作系统 ③login验证程序等待用户登陆 初始化操作系统 kernel加载/sbin/init创建用户空间的第一个程序 该程序完成操作系统的初…...

三周精通FastAPI:3 查询参数
查询参数 FastAPI官网手册:https://fastapi.tiangolo.com/zh/tutorial/query-params/ 上节内容:https://skywalk.blog.csdn.net/article/details/143046422 声明的参数不是路径参数时,路径操作函数会把该参数自动解释为**查询**参数。 from…...

大语言模型学习指南:入门、应用与深入
0x00 学习路径概述 本文将学习路径划分为三个部分:入门篇、应用篇、深入篇。每个章节针对不同的学习需求,帮助你从基础知识入手,逐步掌握大语言模型(LLM)的使用、应用开发以及技术原理等内容。 学习目标 入门篇&…...

【Linux-进程间通信】匿名管道+4种情况+5种特征
匿名管道 匿名管道(Anonymous Pipes)是Unix和类Unix操作系统中的一种通信机制,用于在两个进程之间传递数据。匿名管道通常用于命令行工具之间的数据传递; 匿名管道的工作原理是创建一个临时文件,该文件被称为管道文件…...

Perl打印9x9乘法口诀
本章教程主要介绍如何用Perl打印9x9乘法口诀。 一、程序代码 1、写法① use strict; # 启用严格模式,帮助捕捉变量声明等错误 use warnings; # 启用警告,帮助发现潜在问题# 遍历 1 到 9 的数字 for my $i (1..9) {# 对于每个 $i,遍历 1…...

Android--第一个android程序
写在前边 ※安卓开发工具常用模拟器汇总Android开发者必备工具-常见Android模拟器(MuMu、夜神、蓝叠、逍遥、雷电、Genymotion...)_安卓模拟器-CSDN博客 ※一般游戏模拟器运行速度相对较快,本文选择逍遥模拟器_以下是Android Studio连接模拟器实现(先从以上博文中…...

MySQL的并行复制原理
1. 并行复制的概念 并行复制(Parallel Replication)是一种通过同时处理多个复制任务来加速数据复制的技术。它与并发复制的区别在于,并行复制更多关注的是数据块或事务之间的并行执行,而不是单纯的任务并发。在数据库主从复制中&…...

2023年五一杯数学建模C题双碳目标下低碳建筑研究求解全过程论文及程序
2023年五一杯数学建模 C题 双碳目标下低碳建筑研究 原题再现: “双碳”即碳达峰与碳中和的简称,我国力争2030年前实现碳达峰,2060年前实现碳中和。“双碳”战略倡导绿色、环保、低碳的生活方式。我国加快降低碳排放步伐,大力推进…...

信息安全工程师(57)网络安全漏洞扫描技术与应用
一、网络安全漏洞扫描技术概述 网络安全漏洞扫描技术是一种可以自动检测计算机系统和网络设备中存在的漏洞和弱点的技术。它通过使用特定的方法和工具,模拟攻击者的攻击方式,从而检测存在的漏洞和弱点。这种技术可以帮助组织及时发现并修补漏洞ÿ…...

练习题 - Scrapy爬虫框架 Spider Middleware 爬虫页中间件
在 web 爬虫开发中,Scrapy 是一个非常强大且灵活的框架,它可以帮助开发者轻松地从网页中提取数据。Scrapy 的下载器中间件(Downloader Middleware)是 Scrapy 处理下载请求和响应的一个重要组件。通过使用和编写下载器中间件,开发者可以自定义请求的处理过程,增加请求头信…...

探索C++的工具箱:双向链表容器类list(1)
引言 在C中,std::list 是一个标准库提供的容器类,属于C STL(标准模板库)。std::list 是一种独特而强大的容器,它使用双向链表结构来管理元素。无论是在处理动态数据集合,还是在需要频繁进行插入和删除操作时…...

大厂高频算法考点--单调栈
什么是单调栈: 单调栈就是借助一个栈,在仅仅使用当前栈的条件下,时间复杂度是N(n),将每个节点最有离这他最近的大于或者是小于的数据返回,将已知数组的元素放到栈里。再自我实现的代码里面我们使用数组实现…...

Unity使用Git及GitHub进行项目管理
git: 工作区,暂存区(存放临时要存放的内容),代码仓库区1.初始化 git init 此时展开隐藏项目,会出现.git文件夹 2.减小项目体积 touch .gitignore命令 创建.gitignore文件夹 gitignore文件夹的内容 gitignore中添加一下内容 # This .gitignore file should be place…...