蓝桥杯备赛——“双指针”“三指针”解决vector相关问题

news2025/2/11 16:39:22

一、寄包柜

相关代码:

#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;:定义两个整数变量 nqn 未在代码中使用,q 表示操作的次数。
  • vector<int> a[N];:创建一个包含 Nvector<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;:从标准输入读取两个整数 nq,分别表示柜子数量(实际未使用)和操作次数。
  • 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 = -1cur 是一个辅助变量,用于记录当前非零元素应该放置的位置。初始化为 -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 = -1left 指针用于标记 0 元素区域的右边界,初始化为 -1,表示初始时 0 元素区域为空。
  • int right = nright 指针用于标记 2 元素区域的左边界,初始化为 n,表示初始时 2 元素区域为空。
  • int i = 0i 是当前正在处理的元素的索引,从数组的第一个元素开始。
  • 循环条件while(i < right),只要当前处理的元素索引 i 小于 2 元素区域的左边界 right,就继续循环。
  • 处理当前元素 nums[i] 的三种情况
    1. nums[i] == 0
      • 如果当前元素是 0,将其交换到 0 元素区域的末尾。++left 先将 left 指针右移一位,指向 0 元素区域的下一个位置,然后使用 swap(nums[++left], nums[i++]) 交换 nums[left]nums[i] 的值,并且 i 指针也右移一位,继续处理下一个元素。
    2. nums[i] == 1
      • 如果当前元素是 1,不需要进行交换,直接将 i 指针右移一位,继续处理下一个元素。因为 1 元素应该位于数组的中部,当前位置就是合适的位置。
    3. nums[i] == 2
      • 如果当前元素是 2,将其交换到 2 元素区域的开头。--right 先将 right 指针左移一位,指向 2 元素区域的前一个位置,然后使用 swap(nums[--right], nums[i]) 交换 nums[right]nums[i] 的值。注意这里 i 指针不移动,因为交换过来的元素还需要再次判断。

复杂度分析

  • 时间复杂度:\(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];
 }
};

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

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

相关文章

【Java 面试 八股文】Redis篇

Redis 1. 什么是缓存穿透&#xff1f;怎么解决&#xff1f;2. 你能介绍一下布隆过滤器吗&#xff1f;3. 什么是缓存击穿&#xff1f;怎么解决&#xff1f;4. 什么是缓存雪崩&#xff1f;怎么解决&#xff1f;5. redis做为缓存&#xff0c;mysql的数据如何与redis进行同步呢&…

【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 白苹果变黑苹果

原帖&#xff1a;https://www.bilibili.com/video/BV13V411c7xz/MAC OS系统发布了最新的Sonoma&#xff0c;超酷的动效锁屏壁纸&#xff0c;多样性的桌面小组件&#xff0c;但是也阉割了很多老款机型的升级权利&#xff0c;所以我们可以逆向操作&#xff0c;依旧把老款MAC设备强…

如何使用C++将处理后的信号保存为PNG和TIFF格式

在信号处理领域&#xff0c;我们常常需要将处理结果以图像的形式保存下来&#xff0c;方便后续分析和展示。C提供了多种库来处理图像数据&#xff0c;本文将介绍如何使用stb_image_write库保存为PNG格式图像以及使用OpenCV库保存为TIFF格式图像。 1. PNG格式保存 使用stb_ima…

探索从传统检索增强生成(RAG)到缓存增强生成(CAG)的转变

在人工智能快速发展的当下&#xff0c;大型语言模型&#xff08;LLMs&#xff09;已成为众多应用的核心技术。检索增强生成&#xff08;RAG&#xff09;&#xff08;RAG 系统从 POC 到生产应用&#xff1a;全面解析与实践指南&#xff09;和缓存增强生成&#xff08;CAG&#x…

尝试一下,交互式的三维计算python库,py3d

py3d是一个我开发的三维计算python库&#xff0c;目前不定期在PYPI上发版&#xff0c;可以通过pip直接安装 pip install py3d 开发这个库主要可视化是想把自己在工作中常用的三维方法汇总积累下来&#xff0c;不必每次重新造轮子。其实现成的python库也有很多&#xff0c;例如…

[创业之路-289]:《产品开发管理-方法.流程.工具 》-15- 需求管理 - 第1步:原始需求收集

概述&#xff1a; 需求收集是需求管理的第一步&#xff0c;也是产品开发、项目管理或软件设计中的关键步骤。原始需求收集主要是指从各种来源获取关于产品或服务的初步需求和期望。 以下是对需求管理中的原始需求收集的详细分析&#xff1a; 1、原始需求收集的目的 原始需求…

蓝桥杯---数青蛙(leetcode第1419题)

文章目录 1.题目重述2.例子分析3.思路分析4.思路总结5.代码解释 1.题目重述 这个题目算是模拟这个专题里面的一类比较难的题目了&#xff0c;他主要是使用crock这个单词作为一个整体&#xff0c;让我们确定&#xff1a;给你一个字符串&#xff0c;至少需要多少个青蛙进行完成鸣…

单片机之基本元器件的工作原理

一、二极管 二极管的工作原理 二极管是一种由P型半导体和N型半导体结合形成的PN结器件&#xff0c;具有单向导电性。 1. PN结形成 P型半导体&#xff1a;掺入三价元素&#xff0c;形成空穴作为多数载流子。N型半导体&#xff1a;掺入五价元素&#xff0c;形成自由电子作为多…

OpenEuler学习笔记(二十三):在OpenEuler上部署开源MES系统

在OpenEuler上部署小企业开源MES&#xff08;制造执行系统&#xff0c;Manufacturing Execution System&#xff09;是一个非常有价值的项目&#xff0c;可以帮助企业实现生产过程的数字化管理。以下是基于开源MES系统&#xff08;如 Odoo MES 或 OpenMES&#xff09;的部署步骤…

ubuntu中如何在vscode的终端目录后显示(当前的git分支名) 实测有用

效果展示 配置过程&#xff1a; 在 Ubuntu 中&#xff0c;如果你想在 VS Code 的终端提示符后显示当前的 Git 分支名&#xff0c;可以通过修改 Shell 配置文件&#xff08;如 ~/.bashrc 或 ~/.zshrc&#xff09;来实现。以下是具体步骤&#xff1a; 1. 确定使用的 Shell 首…

从二叉树遍历深入理解BFS和DFS

1. 介绍 1.1 基础 BFS&#xff08;Breadth-First Search&#xff0c;广度优先搜索&#xff09;和 DFS&#xff08;Depth-First Search&#xff0c;深度优先搜索&#xff09;是两种常见的图和树的遍历算法。 BFS&#xff1a;从根节点&#xff08;或起始节点&#xff09;开始&am…

Kotlin协程详解——协程上下文

目录 一、上下文结构 get()获取元素 minusKey()删除元素 fold()元素遍历 plus()添加元素 CombinedContext Key 二、协程名称CoroutineName 三、上下文组合 四、协程作用域CoroutineScope 五、典型用例 协程的上下文&#xff0c;它包含用户定义的一些数据集合&#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…

Deep Dive into LLMs like ChatGPT - by Andrej Karpathy

https://www.youtube.com/watch?v7xTGNNLPyMIhttps://www.youtube.com/watch?v7xTGNNLPyMIDeep Dive into LLMs like ChatGPT - by Andrej Karpathy_哔哩哔哩_bilibilihttps://www.youtube.com/watch?v7xTGNNLPyMI转载自Andrej Karpathy Youtube ChannelThis is a general a…

react实例与总结(一)

目录 一、简单认识 1.1、特点 1.2、JSX语法规则 1.3、函数组件和类式组件 1.4、类组件三大属性state、props、refs 1.4.1、state 1.4.2、props 1.4.3、refs 1.5、事件处理 1.6、收集表单数据—非受控组件和受控组件 1.7、高阶函数—函数柯里化 1.8、生命周期—新旧…

51单片机(国信长天)矩阵键盘的基本操作

在CT107D单片机综合训练平台上&#xff0c;首先将J5处的跳帽接到1~2引脚&#xff0c;使按键S4~S19按键组成4X4的矩阵键盘。在扫描按键的过程中&#xff0c;发现有按键触发信号后(不做去抖动)&#xff0c;待按键松开后&#xff0c;在数码管的第一位显示相应的数字:从左至右&…

STM32 RTC亚秒

rtc时钟功能实现&#xff1a;rtc模块在stm32内部&#xff0c;由电池或者主电源供电。如下图&#xff0c;需注意实现时仅需设置一次初始化。 1、stm32cubemx 代码生成界面设置&#xff0c;仅需开启时钟源和激活日历功能。 2、生成的代码,需要对时钟进行初始化&#xff0c;仅需…

【Linux】深入理解linux权限

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;Linux 目录 前言 一、权限是什么 二、用户和身份角色 三、文件属性 1. 文件属性表示 2. 文件类型 3. 文件的权限属性 四、修改文件的权限属性和角色 1. …

json格式,curl命令,及轻量化处理工具

一. JSON格式 JSON&#xff08;JavaScript Object Notation&#xff09; 是一种轻量级的数据交换格式。它基于一个子集的JavaScript编程语言&#xff0c;使用人类易于阅读的文本格式来存储和表示数据。尽管名字中有“JavaScript”&#xff0c;但JSON是语言无关的&#xff0c;几…