「数组」数组双指针算法合集:二路合并|逆向合并|快慢去重|对撞指针 / LeetCode 88|26|11(C++)

news2025/1/13 15:31:46

目录

概述

1.二路合并

思路

复杂度

Code

2.逆向合并

思路

复杂度

Code

3.快慢去重

思路

复杂度

Code

4.对撞指针

思路

复杂度

Code

总结


概述

数组的线性枚举是我们学习编程时遇到的第一种枚举手段。但是它看起来有点愚蠢:只有一个索引i承担全部的工作,如果有第二个索引j,它总是被嵌套在一次for循环的内部。

像这样:

for (int i = 0;i < n;i++){
   for(int j = i;j < n;j++)
      ...
}

这种行为看起来很直观,但是使得这段代码的复杂度达到了O(n²) 。

但如果我们这样做呢?

for (int i = 0,j = 0;i < n;i++){
   ...
}

在一次循环内维护两个下标索引的行为叫做双指针,如你所见, 这一层for循环的时间复杂度是线性的。

来看看它具体是怎么用的。


1.二路合并

思路

二路合并就是将两个有序数组合成一个有序数组。

我们希望将两个指针指向了两个有序数组,只遍历一次就能够完成合并操作。尽管很简单,但这是归并排序的核心操作之一。

事实上,我们需要三个指针:i,j,k。各自指向两个待合并数组nums1、nums2和承载结果的数组ans。

如果nums1[i]<nums2[j]令承载结果的数组ans[k]获得nums1[i]元素,然后i和k后移一位。

否则ans[k]获得nums2[j]元素,然后j和k后移一位。

你会注意到:每轮循环后i和j分别指向两个数组中的待比较的元素,k指向ans数组的待写入位置

当i或j到达末尾时,将另一方的剩余元素写入ans中。 

复杂度

时间复杂度:O(m+n)

空间复杂度:O(m+n)

m、n:两个数组各自长度

Code

vector<int> merge(vector<int>&a,vector<int>&b){
	const int n=a.size(),m=b.size();
	vector<int>ans(n+m);
	int i=0,j=0,k=0;
	while(i<n&&j<m){
		if(a[i]<b[j])ans[k++]=a[i++];
		else ans[k++]=b[j++];
	}
	while(i<n)ans[k++]=a[i++];
	while(j<m)ans[k++]=b[j++];
	return ans;
}

2.逆向合并

在二路合并中,如果没有承接数组ans怎么办?

给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。

初始化 A 和 B 的元素数量分别为 m 和 n

示例 :

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

思路

但是我们有一个容量很大的A。

考虑这样一个问题:A的后面总是能容纳B,所以我们可以对整个合并操作进行逆向调整,也就是从A末尾的空白区域开始写入元素。

如果你写入了A的元素,那么这意味着前面有一个A元素已经失效了,它被转移到了A末尾,在A的前面删掉一个元素,再在末尾加回来,那么A的空余区不变,仍能容纳B。

如果你写入了B的元素,那么占用一格A的空余区。但是A的空余区只在B完全写入时才被填满。

复杂度

时间复杂度:O(m+n)

空间复杂度:O(1)

Code

void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
    int i=m-1,j=n-1,k=n+m-1;
    while(i>=0&&j>=0){
        if(nums1[i]<nums2[j])nums1[k--]=nums2[j--];
        else nums1[k--]=nums1[i--];
    }
    while(i>=0)nums1[k--]=nums1[i--];
    while(j>=0)nums1[k--]=nums2[j--];
}

3.快慢去重

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

思路

C++标准库在algorithm库下定义了unique函数,实现了这个功能。我们来想一想该怎么实现它。

这种算法必须基于已排序数组实现。 

定义快指针fast向后探索,慢指针slow维护去重区。 

事实上,我们只依靠fast指针来遍历数组,slow做的工作并不是遍历而是维护fast指针探索的结果。

slow总是指向去重区后的第一个待写入位置,slow-1则为去重区的最后一个位置。

每次都依靠fast指针与slow-1进行比对,然后将可行元素写入slow位置处,随后slow++。

注意要从下标1开始。

复杂度

时间复杂度:O(n)

空间复杂度:O(1)

Code

int removeDuplicates(vector<int>& nums) {
    const int n=nums.size();
    int slow=1,fast=1;
    for(;fast<n;fast++)
       if(nums[fast]!=nums[slow-1])
         nums[slow++]=nums[fast];
    return slow;
}

4.对撞指针

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

示例 :

 

d63975869651051e4be5f94a25193e73.jpeg

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

思路

对撞指针从两个方向同时遍历数组。

定义i=0,j=n-1;分别从两侧向内收缩。

双向遍历往往只收缩i和j的其中一个指针,这意味着我们需要知道i右移和j左移的条件。

我们认识到这样一个问题:遍历时容器底的长度总是减小的。因此,如果希望收缩双指针时容量还能增大,那么必须是指针元素小的一方收缩:容器容量总是由他的短边决定。

复杂度

时间复杂度:O(n)

空间复杂度:O(1)

Code

int maxArea(vector<int>& height) {
    int len=height.size();
    int ans=(len-1)*min(height[0],height[len-1]);
    for(int i=0,j=len-1;i<j;){
       int V=(j-i)*min(height[j],height[i]);
       if(V>ans)ans=V;
       if(height[j]>height[i])i++;
       else j--;
    }
    return ans;
}

总结

双指针是一种简单而又灵活的技巧和思想,单独使用可以轻松解决一些特定问题,和其他算法结合也能发挥多样的用处。

我们后续将讲解滑动窗口思想,他也是一类双指针问题。

 

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

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

相关文章

美食攻略系统---附源码99630

摘要 本论文旨在探讨如何利用SpringBoot技术开发一个美食攻略系统。系统将按照软件开发流程&#xff0c;采用B/S架构和面向对象编程思想进行项目开发。在引言部分&#xff0c;将介绍美食攻略系统的背景和开发目的&#xff0c;后续章节将依据软件开发流程&#xff0c;对系统进行…

电路笔记(PCB):数字信号的带宽与上升沿时间经验公式 BW = \frac{0.35}{T_r}

数字信号的带宽由上升沿决定 1. 传输线路的带宽如果小于信号的带宽就会产生失真 带宽限制和失真&#xff1a;当信号通过带宽受限的传输线路时&#xff0c;如果线路的带宽小于信号的带宽&#xff0c;信号的高频成分将被削弱或完全滤除。这种削弱会导致信号失真&#xff0c;特别…

Luma 1.5正式发布,文生视频加强真实感,时长最长5秒

距离上次版本发布仅过去了两个月&#xff0c;Luma AI再次发布了升级版本Dream Machine 1.5。新版本具有更好的文本到视频转换、更智能地提示理解、自定义文本渲染和改进图像到视频的功能。 得益于Luma AI对所有公众开放&#xff0c;任何人都可以免费试用&#xff0c;平台用户在…

CANoe.DiVa的应用——生成TP层测试用例过程流程详解(二)

🙋‍♂️【Vector CANdelastudio配置CDD】文章合集💁‍♂️点击跳转 ——————————————————————————————————–—— 从0开始学习CANoe使用 从0开始学习车载测试 相信时间的力量 星光不负赶路者,时光不负有心人。 目录 一.概述2.经典CAN T…

基于x86 平台opencv的图像采集和seetaface6的人脸朝向姿态估计功能

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 配置资源文件3.2 验证功能一、概述 本文档是针对x86 平台opencv的图像采集和seetaface6的人脸朝向姿态估计功能,opencv通过摄像头采集视频图像,将采集的视频图像送给seetaface6的人脸朝向姿态…

JavaEE 第15节 JUC相关组件介绍

目录 前言&#xff1a; Callable ReentrantLock Semaphore CountDownLatch 前言&#xff1a; 在Java中&#xff0c;JUC&#xff08;包路径&#xff1a;java.util.concurrent&#xff09;是一个用于并发编程的包&#xff0c;提供了线程安全的集合类、同步工具、并发执行框…

OSPF配置学习笔记

1.OSPF基础配置命令 1.1&#xff08;系统视图&#xff09;创建并运行OSPF进程 [Huawei] ospf [ process-id | router-id router-id ] porcess-id用于标识OSPF进程&#xff0c;默认进程号为1。OSPF支持多进程&#xff0c;在同一台设备上可以运行多个不同的OSPF进程&#xff0…

[000-01-022].第09节:RabbitMQ中的消息分发策略

我的后端学习大纲 RabbitMQ学习大纲 1.不公平分发&#xff1a; 1.1.什么是不公平分发&#xff1a; 1.在最开始的时候我们学习到 RabbitMQ 分发消息采用的轮训分发&#xff0c;但在某种场景下这种策略并不是很好&#xff0c;比方说有两个消费者在处理任务&#xff0c;其中有个…

【机器学习】联邦学习技术

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 引言联邦学习的定义与原理联邦学习的用例联邦学习示例与代码 引言 在大数据时代&#xff0c;数据隐私和安全成为了一个日益重要的议题。传统的机器学习模型训练通常需要集中大量数据到一个中心服务器…

【自然语言处理】 构建文本对话系统

构建文本对话系统的框架如下&#xff1a; 根据聊天系统目的功用的不同&#xff0c;可分成三大类型&#xff1a; 闲聊式机器人&#xff1a;较有代表性的有微软小冰、微软小娜、苹果的 Siri、小 i 机器人等&#xff0c;主要以娱乐为目的。 **知识问答型机器人&#xff1a;**知识…

Linux别名与用户管理体系

一、别名 1、概述 别名&#xff0c;给命令进行设置 一般用于给命令设置一个昵称/爱称 主要应用场景: 给常用命令设置个快捷方式&#xff0c;使用简单方便给危险命令加上的防护措施 查看系统已有的别名 [rootyunwei ~]# alias alias cpcp -i alias egrepegrep --coloraut…

[alien Invasion]python小游戏阶段总结

以后可能还会进行代码重构&#xff0c;以最终版本为准 本篇文章旨在理清程序脉络&#xff0c;方便以后写类似的程序时提供一个习惯的思路 未经允许&#xff0c;禁止转载 实体区 ship.py import pygame class Ship():def __init__(self,screen,ai_settings):#储存以便后续使…

RocketMQ广播模式消费失败是否会重试?

文章目录 前言继续广播和集群模式的消费流程集群模式&#xff08;默认的&#xff09;广播模式小结 push和pull介绍源码展示 偏移量保存失败情况1. 网络问题2. Consumer本地问题3. 消费进度记录器问题4. 程序设计问题5. 异常终止6. 持久化策略问题7. 同步问题 源码解析OffsetSto…

亚马逊测评号生存法则:如何抵御亚马逊封号风波?

距离黑五购物狂欢节还剩99天&#xff0c;相信各位商家都在紧锣密鼓的筹备相关事宜&#xff0c;然而&#xff0c;亚马逊的封号风波再次席卷而来。那如何在这场风暴中让亚马逊矩阵测评号安全航行亦或是脱颖而出呢&#xff1f;本文将给你一个答案&#xff0c;并帮助你的亚马逊店铺…

【PyTorch快速入门教程】03 PyTorch基础知识

在PyTorch中&#xff0c;最小的计算单元是张量&#xff08;tensor&#xff09;。因此关于张量的学习还是至关重要的。通过本章节学习&#xff0c;希望你对张量有一个更清晰的了解。 文章目录 1 什么是Tensor2 PyTorch中Tensor使用2.1 创建Tensor2.1.1 直接创建Tensor2.1.2 间接…

anaconda上安装pytorch

1、选择anaconda prompt 2、创建虚拟环境 3、激活进入虚拟环境 4、安装pytorch 怎么得到上面的这串命令&#xff1f; 输入nvidia-smi&#xff0c;查看cuda的版本号为11.7 我这里选择安装cuda的版本号为11.3&#xff0c;满足向下兼容即可。 在安装深度学习环境时&#xff0c;要…

探索《黑神话·悟空》背后的AI技术支持:英伟达全景光线追踪技术、DLSS 3.5 与帧生成

引言 2023 年&#xff0c;游戏《黑神话悟空》以其震撼的视觉效果和深度沉浸的游戏体验&#xff0c;成为全球玩家热议的焦点。这款游戏在发布初期就取得了惊人的销量&#xff1a;预售阶段便突破 120 万套&#xff0c;而发售首日更是达到 450 万份的惊人成绩。这个现象级作品背后…

走进 “星星的孩子” 的世界:理解与关爱儿童自闭症

在这个充满生机与活力的世界里&#xff0c;有一群特殊的孩子&#xff0c;他们仿佛来自遥远的星球&#xff0c;沉浸在自己的独特世界中&#xff0c;难以与外界进行有效的沟通和互动。他们是自闭症儿童&#xff0c;也被称为 “星星的孩子”。 自闭症&#xff0c;又称孤独症谱系障…

Linux 软件编程 数据库

1. 大批量数据存储和管理时使用数据库 2.创建表 create table 表名称(列1 数据类型, 列2 数据类型, ...); 3.插入表 insert into 表名称 values(值1, 值2, ...); 4.查看表 select 列1,列2,... from 表名称 where 匹配条件 order by 列名称 asc/desc; 5.删除表 delete from …

种田RPG游戏(五)

一、重新设置物品栏 1、打开Scripts-Inventory文件新建 ItemSlotData.cs using System.Collections; using System.Collections.Generic; using UnityEngine;[System.Serializable] //单独的类 public class ItemSlotData {public ItemData itemData;//ItemData对象&#xff…