【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

之后我们只需要考虑三种情况

  1. 终止条件
  2. 越界情况
  3. 有几种可能性

代码详解

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);}
};

大楼轮廓线问题 ()

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《PP-OCRv1》论文精读:PaddleOCR是目前SOTA级别的OCR开源技术(截止2024年10月)

PP-OCR: A Practical Ultra Lightweight OCR System论文地址PP-OCRv2: Bag of Tricks for Ultra Lightweight OCR System论文地址PP-OCRv3: More Attempts for the Improvement of Ultra Lightweight OCR System论文地址PaddleOCR Github OCR工具库 43.5K个star PP-OCRv1由百度…

医院信息化与智能化系统(6)

医院信息化与智能化系统(6) 这里只描述对应过程&#xff0c;和可能遇到的问题及解决办法以及对应的参考链接&#xff0c;并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图&#xff0c;可以试试PlantUML&#xff0c;告诉GPT你的文件结构&#xff0c;让他给你对应的…

Java项目-基于springboot框架的疫苗接种管理系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

PYQT5 简单项目实践

在VSCode编辑器我们通过引入pyqt5&#xff0c;用QTdesigner 实现拖拽实现图形化界面 下面我们实现一个简单项目实践一下吧 效果图&#xff1a; 用法&#xff1a;Python编写逻辑&#xff0c;用pyqt实现界面显示。 功能&#xff1a; 第一行把处理的数据文件拖拽到文本框中第二…

powerdesign字体太小,powerdesign Sql preview字体太小

一。powerdesign字体太小修改兼容性 右键点击PowerDesign软件图标-->点击属性-->兼容性-->点击下图中的红框 打勾“使用此设置修复此程序的缩放问题&#xff0c;而不是设置中的缩放问题” 打勾“替代高DPI缩放行为” 缩放执行改为“系统增强”&#xff0c;确定 重启…

页面中包含多个el-popover,点击其中一个显示,其他的关闭(多个el-popover,click触发,点击都不消失的问题)

问题背景&#xff1a;需求是el-tree中的每个树节点后都有一个按钮&#xff0c;点击触发el-popover的显示&#xff0c;但是由click触发的el-popover&#xff0c;在点击下一个节点时&#xff0c;之前的都不消失。 解决办法&#xff1a;注&#xff1a;最主要的就是:ref"data…

Git_IDEA集成Git

Git_IDEA集成Git 配置 Git 忽略文件 创建忽略规则文件 引用忽略配置文件 定位 Git 程序 初始化本地库 添加到暂存区 提交到本地库 切换版本 创建分支 切换分支 合并分支 解决冲突 配置 Git 忽略文件 创建忽略规则文件 引用忽略配置文件 在 .gitconfig 文件中进行&…

房屋租赁网站毕业设计基于SpringBootSSM框架的计算机毕业设计

计算机毕业设计/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序 目录 一、项目背景与目的‌ ‌二、系统需求分析‌ 2.1功能需求 2.2 技术需求 2.3 可执行性 ‌三、系统设计与实现‌ ‌3.1系统架构设计‌&#xff1a; ‌3.2功能模块开发‌&#xff1a; ‌3.3…

AWD的复现

学习awd的相关资料&#xff1a;速成AWD并获奖的学习方法和思考记录- Track 知识社区 - 掌控安全在线教育 - Powered by 掌控者&#xff08;包含使用脚本去批量修改密码&#xff09; 在复现之前去了解了以下AWD的相关脚本 资料&#xff1a;AWD批量攻击脚本使用教程-CSDN博客 …

全新子比主题7.9.2开心版 子比主题最新版源码

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 wordpress zibll子比主题7.9.2开心版 修复评论弹授权 可做付费下载站 含wordpress搭建视频教程zibll子比主题安装视频教程支付配置视频教程&#xff0c;视频都是语音讲解&#xff0c;…

Go:error处理机制和函数

文章目录 error处理机制函数函数作为参数匿名函数匿名函数和闭包闭包运用闭包与工厂模式使用闭包调试 error处理机制 本篇总结的是Go中对于错误的处理机制 Go 语言的函数经常使用两个返回值来表示执行是否成功&#xff1a;返回某个值以及 true 表示成功&#xff1b;返回零值&…

2024软件测试面试秘籍(含答案+文档)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Part1 1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师…

超简洁的B端系统,还是看国外的设计.

国外的一些 B 端系统设计往往注重简洁性和实用性的完美结合。 从界面布局来看&#xff0c;它们通常采用简洁明快的线条和清晰的模块划分&#xff0c;避免了过多的装饰和繁杂的元素&#xff0c;使得用户能够快速聚焦于核心功能。 色彩方面&#xff0c;多选用中性色调或淡雅的色…

自由学习记录(13)

服务端常见的“资源” 在服务端&#xff0c;常见的“资源”指的是服务端提供给客户端访问、使用、处理或操作的各种数据和功能。根据不同类型的服务和应用场景&#xff0c;服务端的资源种类可以非常广泛。以下是一些常见的服务端资源类型&#xff1a; 1. 文件和静态资源 网页…

设计模式04-创建型模式1(简单工厂/工厂模式/抽象工厂/Java)

3.1 简单工厂模式 3.1.1 创建型模式 创建型设计模式将对象的创建过程和对象的使用过程分离&#xff0c;用户使用对象时无需关注对象的创建细节&#xff0c;外界对于这些对象只需要知道它们共同的接口&#xff0c;而不用清楚其实现细节&#xff0c;使得整个系统的设计更加符合…

console.log(“res.data = “ + JSON.stringify(res.data));

res.data[object Object] 说明你在控制台打印 res.data 时&#xff0c;它是一个 JavaScript 对象&#xff0c;而不是字符串。这种情况下&#xff0c;console.log 输出的 [object Object] 表示它无法直接显示对象的内容。 要查看 res.data 的实际内容&#xff0c;你需要将其转换…

​​Spring6梳理17——基于XML的自动装配

以上笔记来源&#xff1a; 尚硅谷Spring零基础入门到进阶&#xff0c;一套搞定spring6全套视频教程&#xff08;源码级讲解&#xff09;https://www.bilibili.com/video/BV1kR4y1b7Qc 目录 ①引入 ②场景模拟 2.1 创建UserController类文件 2.2 创建UserService接口文件 2…

关于jmeter中没有jp@gc - response times over time

1、问题如下&#xff1a; jmeter没有我们要使用的插件 2、解决方法&#xff1a; 选择下面文件&#xff0c;点击应用&#xff1b; 3、问题解决 ps&#xff1a;谢谢观看&#xff01;&#xff01;&#xff01;

Java面向对象(三)(抽象和封装)(自己学习整理的资料)

一.类的提炼过程 从现实生活中归纳总结出&#xff0c;多种相同物种&#xff0c;具有的相同的特性&#xff08;属性&#xff0b;行为&#xff09;提炼到一个容器里&#xff0c;给这个容器起一个名字&#xff0c;名字就是类。 步骤&#xff1a; 发现类&#xff08;Dog&#xff…

亿佰特STM32MP13工业核心板【学习】

资料链接&#xff1a;ebyte.com/serchlist.aspx?keyECK10 加屏蔽罩的方法确实可以防EMC干扰防水防潮&#xff1a; 宽度: 16 位宽表示数据总线的宽度&#xff0c;意味着每次可以传输 16 位的数据。这在某些应用中可以提高内存带宽。电压: DDR3L SDRAM 的工作电压通常为 1.35V&…