蓝桥杯备赛——“双指针”“三指针”解决vector相关问题
一、寄包柜


相关代码:
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e5 + 10;
int n, q;
vector<int> a[N]; // 创建 N 个柜⼦
int main()
{cin >> n >> q;while(q--){int op, i, j, k;cin >> op >> i >> j;if(op == 1) // 存 {cin >> k;if(a[i].size() <= j){// 扩容 a[i].resize(j + 1);}a[i][j] = k;}else // 查询 {cout << a[i][j] << endl;}}return 0;
}
代码解读:
const int N = 1e5 + 10;:定义一个常量N,其值为100000 + 10,用于表示柜子的最大数量。int n, q;:定义两个整数变量n和q,n未在代码中使用,q表示操作的次数。vector<int> a[N];:创建一个包含N个vector<int>对象的数组a,每个vector<int>可以看作一个柜子,用于存储整数。
int main()
{cin >> n >> q;while(q--){int op, i, j, k;cin >> op >> i >> j;if(op == 1) // 存 {cin >> k;if(a[i].size() <= j){// 扩容 a[i].resize(j + 1);}a[i][j] = k;}else // 查询 {cout << a[i][j] << endl;}}return 0;
}
cin >> n >> q;:从标准输入读取两个整数n和q,分别表示柜子数量(实际未使用)和操作次数。while(q--):循环q次,每次处理一个操作。int op, i, j, k;:定义四个整数变量,op表示操作类型,i表示柜子编号,j表示格子编号,k表示要存入的值。cin >> op >> i >> j;:从标准输入读取操作类型、柜子编号和格子编号。if(op == 1):如果操作类型为 1,表示存储操作。cin >> k;:从标准输入读取要存入的值k。if(a[i].size() <= j):检查当前柜子a[i]的大小是否小于等于要存入的格子编号j。a[i].resize(j + 1);:如果是,则对柜子a[i]进行扩容,使其大小至少为j + 1。
a[i][j] = k;:将值k存入柜子a[i]的第j个格子中。
else:如果操作类型不为 1,表示查询操作。cout << a[i][j] << endl;:输出柜子a[i]的第j个格子中存储的值,并换行。
复杂度分析
- 时间复杂度:对于存储操作,如果需要扩容,时间复杂度为 \(O(j)\),因为
resize操作可能需要重新分配内存并复制元素;对于查询操作,时间复杂度为 \(O(1)\)。 - 空间复杂度:主要取决于存储的元素数量,最坏情况下为 \(O(N * M)\),其中 \(N\) 是柜子的数量,\(M\) 是每个柜子中格子的最大数量。
二、移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
提示:

解法:
在本题中,我们可以⽤⼀个 指针来扫描整个数组,另⼀个 指针⽤来记录⾮零数序列的最后
⼀个位置。根据 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。
cur dest
cur
在cur 遍历期间,使[0, dest] 的元素全部都是⾮零元素,[dest + 1, cur − 1] 的元素全是零。
如下图:

①当扫描元素是0的时候,我们要想让它出现在中间的区间中,因此我们只需让i++就可以了。
②当扫描元素是非零元素的时候,我们想让它出现在第一个区间中,因此我们要交换当前元素和cur+1所指向的元素,也就是【cur+1】和【i】。交换完之后让cur++,i++。
代码演示:
class Solution
{
public:void moveZeroes(vector<int>& nums) {for(int i = 0, cur = -1; i < nums.size(); i++){if(nums[i]) // ⾮0元素 {swap(nums[++cur], nums[i]);}}}
};
代码解读:
-
变量初始化:
int i = 0:这是一个循环变量,用于遍历向量nums中的每个元素,从索引 0 开始。int cur = -1:cur是一个辅助变量,用于记录当前非零元素应该放置的位置。初始化为 -1,表示还没有遇到非零元素。
-
循环遍历:
i < nums.size():循环条件,确保i在向量的有效索引范围内。i++:每次循环结束后,i自增 1,指向下一个元素。
-
条件判断:
if(nums[i]):这是一个条件判断语句,判断当前元素nums[i]是否为非零元素。在 C++ 中,非零值被视为true,零值被视为false,所以这个条件等价于if(nums[i] != 0)。
-
交换操作:
swap(nums[++cur], nums[i]):如果当前元素nums[i]是非零元素,执行以下操作:++cur:先将cur的值加 1,使其指向下一个可以放置非零元素的位置。swap(...):使用swap函数交换nums[cur]和nums[i]的值。这样,非零元素就会被依次移动到向量的前面,而零元素会被逐渐挤到向量的后面。
复杂度分析
- 时间复杂度:\(O(n)\),其中 \(n\) 是向量
nums的长度。因为代码只对向量进行了一次遍历,每个元素最多被访问和交换一次。 - 空间复杂度:\(O(1)\),只使用了常数级的额外空间,没有使用与向量长度相关的额外数据结构。
示例调用
#include <iostream>
#include <vector>class Solution
{
public:void moveZeroes(std::vector<int>& nums) {for(int i = 0, cur = -1; i < nums.size(); i++){if(nums[i]) // ⾮0元素 {std::swap(nums[++cur], nums[i]);}}}
};int main() {std::vector<int> nums = {0, 1, 0, 3, 12};Solution sol;sol.moveZeroes(nums);for (int num : nums) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
在上述示例中,我们创建了一个包含 0 和非零元素的向量 nums,调用 Solution 类的 moveZeroes 函数对其进行处理,最后输出处理后的向量。运行代码后,输出结果将是 1 3 12 0 0,即所有 0 元素都被移动到了向量的末尾,非零元素的相对顺序保持不变。
三、颜色分类
【题⽬描述】
给定⼀个包含红⾊、⽩⾊和蓝⾊、共 个元素的数组 ,原地对它们进⾏排序,使得相同颜
⾊的元素相邻,并按照红⾊、⽩⾊、蓝⾊顺序排列。
n nums
我们使⽤整数0 、1 和2 分别表⽰红⾊、⽩⾊和蓝⾊。
必须在不使⽤库的sort 函数的情况下解决这个问题。
【⽰例⼀】
输⼊:
nums=[2,0,2,1,1,0]
输出:
[0,0,1,1,2,2]
解法
类⽐数组分两块的算法思想,这⾥是将数组分成三块,那么我们可以再添加⼀个指针,实现数组分三块。
设数组⼤⼩为n ,定义三个指针left, cur, right :
• left :⽤来标记0 序列的末尾,因此初始化为−1 ;• cur :⽤来扫描数组,初始化为0 ;
• right :⽤来标记2 序列的起始位置,因此初始化为n 。
在cur 往后扫描的过程中,保证:
• [0, left] 内的元素都是0 ;
• [left + 1, cur − 1] 内的元素都是1 ;
• [cur, right − 1] 内的元素是待定元素;
• [right, n] 内的元素都是2 。

①当扫描到1的时候,我们想把它放到中间第二个区间里面,因此我们可以让i++即可实现。
②当扫描到0的时候,我们想把它放到第一个区间中,因此我们可以让i和left+1进行交换,然后left++,i++。
③当扫描到2的时候,我们想把它放到最后一个区间中,因此我们交换i和right-1,然后right--。但是i得位置是不可以动的。(因为right-1原先是带扫描区域的数,和i交换之后需要再次判断)
代码如下:
class Solution
{
public:void sortColors(vector<int>& nums) {int n = nums.size();int left = -1, right = n, i = 0;while(i < right){if(nums[i] == 0) swap(nums[++left], nums[i++]);else if(nums[i] == 1) i++;else swap(nums[--right], nums[i]);}}
};
代码解读:
class Solution:定义了一个名为Solution的类,用于封装解决特定问题的方法。void sortColors(vector<int>& nums):定义了一个公共成员函数sortColors,它接受一个整数向量的引用nums作为参数,并且不返回任何值(返回类型为void)。该函数的目的是对传入的向量进行原地排序。
int n = nums.size();:获取向量nums的长度,方便后续使用。int left = -1:left指针用于标记 0 元素区域的右边界,初始化为 -1,表示初始时 0 元素区域为空。int right = n:right指针用于标记 2 元素区域的左边界,初始化为n,表示初始时 2 元素区域为空。int i = 0:i是当前正在处理的元素的索引,从数组的第一个元素开始。
- 循环条件:
while(i < right),只要当前处理的元素索引i小于 2 元素区域的左边界right,就继续循环。 - 处理当前元素
nums[i]的三种情况:nums[i] == 0:- 如果当前元素是 0,将其交换到 0 元素区域的末尾。
++left先将left指针右移一位,指向 0 元素区域的下一个位置,然后使用swap(nums[++left], nums[i++])交换nums[left]和nums[i]的值,并且i指针也右移一位,继续处理下一个元素。
- 如果当前元素是 0,将其交换到 0 元素区域的末尾。
nums[i] == 1:- 如果当前元素是 1,不需要进行交换,直接将
i指针右移一位,继续处理下一个元素。因为 1 元素应该位于数组的中部,当前位置就是合适的位置。
- 如果当前元素是 1,不需要进行交换,直接将
nums[i] == 2:- 如果当前元素是 2,将其交换到 2 元素区域的开头。
--right先将right指针左移一位,指向 2 元素区域的前一个位置,然后使用swap(nums[--right], nums[i])交换nums[right]和nums[i]的值。注意这里i指针不移动,因为交换过来的元素还需要再次判断。
- 如果当前元素是 2,将其交换到 2 元素区域的开头。
复杂度分析
- 时间复杂度:\(O(n)\),其中 \(n\) 是向量
nums的长度。因为代码只对向量进行了一次遍历,每个元素最多被交换一次。 - 空间复杂度:\(O(1)\),只使用了常数级的额外空间,没有使用与向量长度相关的额外数据结构。
四、合并两个数组
给你两个按⾮递减顺序排列的整数数组 和 ,另有两个整数 和 ,分别表⽰
和 中的元素数⽬。
nums1 nums2 m n
nums1 nums2
请你合并nums2 到nums1 中,使合并后的数组同样按⾮递减顺序排列。注意:最终,合并后数组不应由函数返回,⽽是存储在数组 中。为了应对这种情况,
的初始⻓度为 ,其中前 个元素表⽰应合并的元素,后 个元素为 ,应忽
略。 的⻓度为 。
nums1
nums1 m + n m n 0
nums2 n
【⽰例⼀】
输⼊:
nums1=[1,2,3,0,0,0],m=3,nums2=[2,5,6],n=3
输出:
[1,2,2,3,5,6]
解法⼀:利⽤辅助数组(需要学会,归并排序的核⼼步骤)
可以创建⼀个辅助数组,然后⽤两个指针分别指向两个数组。每次拿出⼀个较⼩的元素放在辅助数组中,直到把所有元素全部放在辅助数组中。最后把辅助数组的结果覆盖到nums1 中。
lass Solution
{
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {// 解法⼀:利⽤辅助数组 vector<int> tmp(m + n);int cur = 0, cur1 = 0, cur2 = 0;while(cur1 < m && cur2 < n){if(nums1[cur1] <= nums2[cur2]) tmp[cur++] = nums1[cur1++];else tmp[cur++] = nums2[cur2++];}while(cur1 < m) tmp[cur++] = nums1[cur1++];while(cur2 < n) tmp[cur++] = nums2[cur2++];for(int i = 0; i < n + m; i++) nums1[i] = tmp[i];}
};
相关文章:
蓝桥杯备赛——“双指针”“三指针”解决vector相关问题
一、寄包柜 相关代码: #include <iostream> #include <vector> using namespace std; const int N 1e5 10; int n, q; vector<int> a[N]; // 创建 N 个柜⼦ int main() {cin >> n >> q;while(q--){int op, i, j, k;cin >> …...
【Java 面试 八股文】Redis篇
Redis 1. 什么是缓存穿透?怎么解决?2. 你能介绍一下布隆过滤器吗?3. 什么是缓存击穿?怎么解决?4. 什么是缓存雪崩?怎么解决?5. redis做为缓存,mysql的数据如何与redis进行同步呢&…...
SIPp的参数及命令示例
以下是SIPp参数的分类表格整理,方便快速查阅和使用: SIPp 参数分类表格 分类参数描述默认值示例基本参数-sc指定XML场景文件(客户端模式)无-sc uac.xml-sd指定XML场景文件(服务器端模式)无-sd uas.xml-i本…...
全面理解-友元(friend关键字)
在 C 中,friend 关键字用于授予其他类或函数访问当前类的 私有(private)和保护(protected)成员 的权限。这种机制打破了严格的封装性,但可以在特定场景下提高代码的灵活性和效率。以下是 friend 的详细说明…...
【Java】多线程和高并发编程(三):锁(下)深入ReentrantReadWriteLock
文章目录 4、深入ReentrantReadWriteLock4.1 为什么要出现读写锁4.2 读写锁的实现原理4.3 写锁分析4.3.1 写锁加锁流程概述4.3.2 写锁加锁源码分析4.3.3 写锁释放锁流程概述&释放锁源码 4.4 读锁分析4.4.1 读锁加锁流程概述4.4.1.1 基础读锁流程4.4.1.2 读锁重入流程4.4.1.…...
macbook2015升级最新MacOS 白苹果变黑苹果
原帖:https://www.bilibili.com/video/BV13V411c7xz/MAC OS系统发布了最新的Sonoma,超酷的动效锁屏壁纸,多样性的桌面小组件,但是也阉割了很多老款机型的升级权利,所以我们可以逆向操作,依旧把老款MAC设备强…...
如何使用C++将处理后的信号保存为PNG和TIFF格式
在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示。C提供了多种库来处理图像数据,本文将介绍如何使用stb_image_write库保存为PNG格式图像以及使用OpenCV库保存为TIFF格式图像。 1. PNG格式保存 使用stb_ima…...
探索从传统检索增强生成(RAG)到缓存增强生成(CAG)的转变
在人工智能快速发展的当下,大型语言模型(LLMs)已成为众多应用的核心技术。检索增强生成(RAG)(RAG 系统从 POC 到生产应用:全面解析与实践指南)和缓存增强生成(CAG&#x…...
尝试一下,交互式的三维计算python库,py3d
py3d是一个我开发的三维计算python库,目前不定期在PYPI上发版,可以通过pip直接安装 pip install py3d 开发这个库主要可视化是想把自己在工作中常用的三维方法汇总积累下来,不必每次重新造轮子。其实现成的python库也有很多,例如…...
[创业之路-289]:《产品开发管理-方法.流程.工具 》-15- 需求管理 - 第1步:原始需求收集
概述: 需求收集是需求管理的第一步,也是产品开发、项目管理或软件设计中的关键步骤。原始需求收集主要是指从各种来源获取关于产品或服务的初步需求和期望。 以下是对需求管理中的原始需求收集的详细分析: 1、原始需求收集的目的 原始需求…...
蓝桥杯---数青蛙(leetcode第1419题)
文章目录 1.题目重述2.例子分析3.思路分析4.思路总结5.代码解释 1.题目重述 这个题目算是模拟这个专题里面的一类比较难的题目了,他主要是使用crock这个单词作为一个整体,让我们确定:给你一个字符串,至少需要多少个青蛙进行完成鸣…...
单片机之基本元器件的工作原理
一、二极管 二极管的工作原理 二极管是一种由P型半导体和N型半导体结合形成的PN结器件,具有单向导电性。 1. PN结形成 P型半导体:掺入三价元素,形成空穴作为多数载流子。N型半导体:掺入五价元素,形成自由电子作为多…...
Spring Boot + MyBatis Field ‘xxx‘ doesn‘t have a default value 问题排查与解决
目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 执行代码的时候,出现某个字段无法添加 ### Error updating database. Cause: java.sql.SQLException: Field e_f_id doesnt have a default value ### The error may exist in cn...
C++ STL Map 学习学案(提高版)
C++ STL Map 学案(初中生版) 一、学习目标 深入理解 STL 中 map 容器的概念、特点和用途。熟练掌握 map 容器的基本操作,如插入、查找、删除和遍历元素。能够运用 map 容器解决实际编程问题,提升逻辑思维和编程实践能力。二、知识讲解 引入 在日常生活中,我们常常会遇到…...
OpenEuler学习笔记(二十三):在OpenEuler上部署开源MES系统
在OpenEuler上部署小企业开源MES(制造执行系统,Manufacturing Execution System)是一个非常有价值的项目,可以帮助企业实现生产过程的数字化管理。以下是基于开源MES系统(如 Odoo MES 或 OpenMES)的部署步骤…...
深入与浅出-Python爬虫逆向实战
一、什么是爬虫逆向? 爬虫逆向,简单来说,就是通过分析网页的前端和后端行为,找出数据的来源和获取方式,从而实现自动化抓取。很多时候,直接使用requests和BeautifulSoup可能无法获取到目标数据,…...
ubuntu中如何在vscode的终端目录后显示(当前的git分支名) 实测有用
效果展示 配置过程: 在 Ubuntu 中,如果你想在 VS Code 的终端提示符后显示当前的 Git 分支名,可以通过修改 Shell 配置文件(如 ~/.bashrc 或 ~/.zshrc)来实现。以下是具体步骤: 1. 确定使用的 Shell 首…...
什么是自回归范式
Autoregressive Paradigm(自回归范式)是一种广泛应用于 序列数据建模 的方法,它在生成模型中发挥着重要作用。自回归范式的核心思想是 基于已知的历史信息(或前一个状态),来预测下一个值。这种方法在 时间序…...
Jenkins 使用教程:从入门到精通
在软件开发的复杂流程中,持续集成与持续交付(CI/CD)是提升开发效率和保障软件质量的核心实践。Jenkins 作为一款备受欢迎的开源自动化服务器,在 CI/CD 流程中发挥着举足轻重的作用。本文将深入、详细地介绍 Jenkins 的使用方法&am…...
DeepSeek大模型的微调流程
DeepSeek大模型的微调流程通常包括以下几个步骤: 1. 环境准备 硬件:确保有足够的GPU资源,通常需要高性能GPU(如NVIDIA A100、V100等)。软件:安装必要的深度学习框架(如PyTorch、TensorFlow&am…...
关于“i18n“在vue中的使用
关于"i18n"在vue中的使用 <!-- vue2中 --> <template><div>{{ $t("This campaign has expired.") }}}}</div> </template> <script> export default {created() {this.onLoading();},methods: {onLoading () {this.$…...
Android图片加载框架Coil,Kotlin
Android图片加载框架Coil,Kotlin implementation("io.coil-kt:coil:1.4.0") import android.os.Bundle import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import coil.Coil i…...
从二叉树遍历深入理解BFS和DFS
1. 介绍 1.1 基础 BFS(Breadth-First Search,广度优先搜索)和 DFS(Depth-First Search,深度优先搜索)是两种常见的图和树的遍历算法。 BFS:从根节点(或起始节点)开始&am…...
强化学习之 PPO 算法:原理、实现与案例深度剖析
目录 一、引言二、PPO 算法原理2.1 策略梯度2.2 PPO 核心思想 三、PPO 算法公式推导3.1 重要性采样3.2 优势函数估计 四、PPO 算法代码实现(以 Python 和 PyTorch 为例)五、PPO 算法案例应用5.1 机器人控制5.2 自动驾驶 六、总结 一、引言 强化学习作为…...
Docker 部署 MongoDB | 国内阿里镜像
一、简易单机版 1、镜像拉取 docker pull registry.cn-hangzhou.aliyuncs.com/farerboy/mongo:8.0.5-rc1 2、运行镜像 docker run -it --name mongodb \ -e MONGO_INITDB_ROOT_USERNAMEmongoroot \ -e MONGO_INITDB_ROOT_PASSWORDmongoroot \ -v /wwwroot/opt/docker/mong…...
1.1 Spring Security 概述
Spring Security 概述 1. 什么是 Spring Security? Spring Security 是 Spring 生态中专注于应用安全的核心框架,为 Java 企业应用提供认证(Authentication)、授权(Authorization)以及安全攻击防护&#x…...
Kotlin协程详解——协程上下文
目录 一、上下文结构 get()获取元素 minusKey()删除元素 fold()元素遍历 plus()添加元素 CombinedContext Key 二、协程名称CoroutineName 三、上下文组合 四、协程作用域CoroutineScope 五、典型用例 协程的上下文,它包含用户定义的一些数据集合&#x…...
手写一个C++ Android Binder服务及源码分析
手写一个C Android Binder服务及源码分析 前言一、 基于C语言编写Android Binder跨进程通信Demo总结及改进二、C语言编写自己的Binder服务Demo1. binder服务demo功能介绍2. binder服务demo代码结构图3. binder服务demo代码实现3.1 IHelloService.h代码实现3.2 BnHelloService.c…...
今日AI和商界事件(2025-02-10)
今日AI领域的相关事件包括: 一、技术与应用进展 全球首例AI驱动供应链攻击曝光: 网络安全机构披露一起新型供应链攻击事件,攻击者利用AI技术生成高度仿真的供应商邮件,诱骗目标企业员工下载恶意软件,进而渗透至大众汽…...
全面理解-c++中的异常处理机制
C 的异常处理机制是一种用于处理程序运行时错误的结构化方法,通过分离正常逻辑与错误处理代码,提高代码的可读性和可维护性。以下是其核心组成部分和工作原理的详细说明: 1. 异常处理的三大关键字 1.1 try 块 作用:包裹可能抛出异…...
