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

手把手教你解决CentOS sshd启动报错:从权限问题到目录缺失的全套解决方案 本文提供了一套完整的CentOS SSH服务启动故障排查与修复方案。针对sshd启动报错,从systemd日志分析、sshd -t配置测试入手,详细解决了私钥文件权限过宽(如0644错误)和权限分离目录缺失等典型问题,并附带了扩展排查清单,帮助运维人员系统性地定位和解决连接故障。 阅读详情

目录

概述

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怎么办?

LeetCode 88:

给定两个排序后的数组 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.快慢去重

LeetCode 26:

给你一个 非严格递增排列 的数组 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.对撞指针

LeetCode 11:

给定一个长度为 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;
}

总结

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

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

无人机导航中的坐标系统详解与转换实现 本文系统介绍了无人机导航中常用的坐标系及其转换方法。主要内容包括:1) 四种关键坐标系(大地坐标系ECEF、经纬度LLA、北东天坐标系NED、机体坐标系)的定义和特点;2) 坐标系间的转换原理与实现,重点讲解LLA与ECEF的互转公式及ECEF与NED的转换方法;3) 提供可直接使用的C++实现代码,包括基于WGS84椭球模型的精确转换算法。这些内容为无人机导航系统开发提供了实用的坐标系处理方案,能够有效解决多源数据在不同坐标系下的统一表示问题。 阅读详情

相关推荐

正交试验实战指南:从PICT工具到混合水平表应用

本文详细介绍了正交试验法在测试设计中的实战应用,从基础概念到PICT工具的高级使用技巧。通过混合水平表设计和工程化实践案例,帮助测试工程师高效解决参数组合爆炸问题,提升测试覆盖率与效率。特别适合兼容性测试和复杂系统验证场景。

weixin_29230865的博客 260

二路归并排序算法

将两个按值有序序列合并成一个按值有序序列,则称之为二路归并排序,下面有自底向上和自顶向下的两种排序算法,自顶向下的排序在本文末讲述,使用递归实现,代码较简洁,经供参考。 1. 归并子算法:把位置相邻的两个按值有序序列合并成一个按值有序序列。例如把序列 X[s..u] = {3, 12, 23, 32}和 序列 X[u+1..v] = {2, 5, 8, 99} 合并成序列  Z[s..v] =

CaryaLiu的专栏 4万+

超详细网安学习路线(Day1-Day2)

渗透测试(Penetration Testing),就是一种通过模拟恶意攻击者的技术与方法,挫败目标系统安全控制措施,取得访问控制权,并发现具备业务影响后果安全隐患的一种安全测试与评估方法。简单来说,就是合法去入侵别人的系统,来帮助其找出漏洞,增强防护能力。

aobulaien001的博客 3389

《数据结构》学习系列——排序(下)

系列文章目录目录思想 对待排序的文件进行n次选择,其中第i次选择第i小(大)的记录放在第i(n-i+1)个位置上算法直接选择排序思想:例如,第i趟比较(i=1,…,n−1)在前面n−i+1个待排序记录中选出关键词最大的记录,作为有序记录序列的第n−i+1个记录。待到第n−1趟作完,待排序记录只剩下1个时,算法结束 算法分析 直接选择排序的关键词比较次数与记录的初始排列无关。假定整个待排序文件有nnn个记录,第iii趟选择具有最大关键词的记录所需的比较总次数是n−in-in−i次。因此,总的关键词比较次数为

Kenjuan的博客 1332

ETL数据集成案例

一个典型的ETL数据集成案例是将多个来源的数据合并成一个数据集。假设有一个公司,该公司使用一些不同的系统来存储不同部门的数据,例如销售数据存储在一个CRM系统中,财务数据存储在一个ERP系统中,人力资源数据存储在一个HR系统中。为了更好地进行报告和分析,该公司决定将所有这些数据集成到一个数据仓库中。以下是实现这一目标的ETL过程的步骤:提取(Extract):首先,需要从每个系统中提取所需的数据。每个系统可能有不同的数据格式和结构,因此需要编写不同的提取程序或查询来提取数据。

runqu的博客 948

JavaScript教程-字符集,Unicode转义序列,标识符,数据类型,数字,未定义值,浮点数,字符串,引用数据类型,类型检测,类型转换,运算符,关系运算符,

前端学习

VAN 212

数据结构与算法:二路归并排序(合并排序)

数据结构与算法:二路归并排序/合并排序概述:图解: 概述: List item 图解: 假设我们有这样一组数据 A[9] = {4,3,6,7,9,1,2},他在内存中这样排序

weixin_42585456的博客 4万+

GEE:本地影像上传到GEE的Assets中,并输入机器学习算法中作为特征变量

当我们在 Google Earth Engine(GEE)中应用机器学习算法时,会输入一些影像作为特征变量数据,进一步根据这些特征影像去推理未知区域的数据。但是 GEE 平台上计算特征变量的 API 函数并不是非常全面,我们希望获得更多的特征用于分类。这个时候,我们可以将本地计算的特征影像上传到 GEE 中进行后续处理。本文记录了从本地上传特征数据到 GEE 的 Assets 中的教程,用于后续在 GEE 中分类或者回归使用。本文也可作为《》一文的补充。

养乐多的博客 1730

二路归并算法

二路归并算法 二路归并排序就是将两个有序子表归并成一个有序表。首先我们得有一个算法用于归并:两个有序表放在同一数组的相邻位置上,a[low]到arr[mid]为第一个有序表,a[mid+1]到arr[high]是第二个有序表。每次从两端中取出一个进行比较,小的先放在一个temp数组,最后将比较剩下的直接放到temp中去,最后将temp又复制回arr。这是“治”。 下面说“分”,只需要递归地将前半部分和后半部分的数据各自归并排序即可。 #include <stdio.h> #include &

qkk121的博客 1323

如何将 Fiori Elements Object Page Header 工具栏里按钮用 JavaScript 代码设置成禁用状态

本文介绍了如何在SAP Fiori Elements应用中动态控制Object Page工具栏按钮的可用状态。通过UI5 Inspector工具分析发现,这些按钮的enabled属性都双向绑定到/ui/enabled模型字段。在StatusExt.controller.js中,通过获取按钮ID前缀拼接完整控件ID,使用setEnabled(false)方法即可禁用按钮。关键点包括:1)使用extensionAPI获取视图ID前缀;2)注意事件回调中的this上下文绑定;3)通过修改模型字段可同步更新所有绑定

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 372

virtuoso如何导出def?

在DEF Out界面,填写def name,library name以及cell name ,cell view既layout,把Output "Floating Shapes" into SPECIAL NETS Section勾上,OK即可。2)在要导出的layout界面选中PAD和prBoundary(shift+左键),快捷键C copy到空cell里,这时需要调整copy过来的object坐标,让两边prBoundary的坐标相同。我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?

m0_61544122的博客 2306

双指针技巧1

合并两个有序链表: 给你输入两个有序链表,请你把他俩合并成一个新的有序链表: 核心代码如下: public class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next =.

qq_45905045的博客 908

论文阅读: 2024 ICLR AutoDAN: Generating Stealthy Jailbreak Prompts on Aligned Large Language Models

AutoDAN: Generating Stealthy Jailbreak Prompts on Aligned Large Language Models这篇论文名为“AUTODAN: GENERATING STEALTHY JAILBREAK PROMPTS ON ALIGNED LARGE LANGUAGE MODELS”,主要研究大语言模型(LLMs)的越狱攻击问题,提出了一种名为AutoDAN的新方法,能自动生成隐蔽的越狱提示,具体内容如下:

CSPhD-winston的博客 1177

「数组」定长滑动窗口|不定长滑动窗口 / LeetCode 2461|2958(C++)

滑动窗口是一类经典的双指针问题,它会借用额外的存储结构来维护一段连续的子数组。

dakingffo的博客 1195

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

二路归并

二路归并 题目描述 编写一个程序,使用分治策略实现二路归并排序(升序)。 (图源网络,我忘了哪儿存的了。。。侵删) 输入 多组输入,每组第一个数字为数组长度,然后输入一个一维整型数组。 输出 输出排序之后(升序)的一维整型数组,每组输出占一行。 样例输入 6 1 8 6 5 3 4 5 12 42 2 5 8 样例输出 1 3 4 5 6 8 2 5 8 12 42 了解算法 一、将一个数组拆分为两个部分,一般取数组长度一般的位置为界,分为两个子数组,再分别对这两个子数组进行递归归并排序。 ​

qq_43461438的博客 7401

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

两个有序单链表的合并(二路归并)

第一种算法: 用Lc指向合并后的新表。pa,pb,pc分别作为La,Lb,Lc的工作指针,pa,pb初始化分别指向两个有序链表的第一个元素,pc初始化指向La。从第一个指针开始比较,哪个元素小,就接在Lc后面,如果两个元素相当,就把一个链表接在后面,删除另一个链表的那个元素,这样确保合并后的表内无重复元素。当一个表到达表尾结点为空时,将非空的表接在Lc表后面。 #include"linkl...

WonderKing'blog 1万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

常见的五类排序算法图解和实现(归并类:二路归并排序)

归并类的排序算法 归并:将两个或两个以上的有序表组合成一个新的有序表。 内部排序中,通常采用的是 2-路归并排序。即:将两个位置相邻的记录有序子序列归并为一个记录有序的序列。归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 图解如下 看成是 n 个有序的子序列(长度为 1),然后两两归并。 ...

diaoyanqin5061的博客 1292

git 的合并原理(递归三路合并算法)

如果 git 只是一行行比较,然后把不同的行报成冲突,那么你在合并的时候可能会遇到大量的冲突;这显然不是一个好的版本管理工具。 本文介绍 git 合并分支的原理。 本文内容git 的冲突表示三路合并递归三路合并快进式合并参考资料 git 的冲突表示 例如我们有这样的三个提交 a、b、c。a、b 是在 master 上的其他修改,c 是我自己基于 master 上的 a 的修改。 现在,将 mas...

walterlv - 吕毅 7401

两路合并排序

两路合并排序,时间复杂度为nlogn #include using namespace std; //merge two subArray,one is A[i1]~A[j1],another is A[i2]~A[j2] void MergeTwoArray(int A[],int i1,int j1,int i2,int j2) { int *tmp = new int[j

nuptxiaoli 2265

数据结构-二路归并及归并排序

一、介绍:归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。该算法的核心思想是二路归并。二、二路归并介绍<1>在归并的过程中步骤如下:①设定两个指针(不一定非是指针,只需要记住对应开始下标即可),最初位置分别为两个已

2万+

排序算法之二路归并排序

基本思想首先将待排序的元素序列分成两个长度相等的子序列,为每一个子序列排序,然后再将它们合并成一个序列。代码private void mergeSort(int[] a, int[] b, int left, int right) { if (left < right) { int middle = (left + right) / 2; mergeSort(

语言智能技术笔记簿 3121

归并排序算法 C代码实现

合并排序(MERGE SORT)是又一类不同的排序方法,合并的含义就是将两个或两个以上的有序数据序列合并成一个新的有序数据序列,因此它又叫归并算法。它的基本思想就是假设数组A有N个元素,那么可以看成数组A是又N个有序的子序列组成,每个子序列的长度为1,然后再两两合并,得到了一个 N/2 个长度为2或1的有序子序列,再两两合并,如此重复,值得得到一个长度为N的有序数据序列为止,这种排序方法称为2—路

Gary's Blog --- A C++ programmer 3554

归并排序(二路归并)

直接上代码:

jw903的专栏 661

归并排序:二路归并

归并排序(Merge Sort)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。 归并排序的具体做法: 把原序列不断地递归等分,直至每等份只有一个元素,此时每等份都是有序的。 相邻等份合并,不断合并,直至合并完全。 二路归并 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序最常用的是二路归并,即把两个小的有序的序列和并成一个大的有序序列:合二为一

CCPP Blog 1万+

游戏中的“奇异矩阵”:暗藏玄机的神奇工具——当矩阵不再可逆,世界反而更好玩

奇异矩阵在游戏开发中有独特应用场景:1)阴影投影通过矩阵将3D物体压至平面,丢失z轴信息;2)维度降维实现卡通化特效(如角色压扁成纸);3)特殊动画如角色塌陷或传送效果;4)数学教学可视化降维过程;5)简化碰撞检测至2D平面。典型应用包括投影阴影技术(Unity/Unreal)和恶搞动画效果。尽管奇异矩阵通常引发计算问题,但在这些场景中却能实现特殊维度变换,其核心价值在于可控的信息丢失与空间压缩。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 3512

三路合并 —— Git 学习笔记 17

三路合并 和其他版本控制系统不同,Git 提供的合并冲突解决方案并不会聪明过头,不会尝试自动将所有问题都解决。Git 的设计哲学是智能判断一个合并是否可以非常容易地自动完成,如果自动化方案不可行,就不要自作聪明地去尝试解决它,最好让用户自己去解决合并冲突。 文件层面 通过比较共同的祖先(base)、当前分支(ours),待合并分支(theirs),Git 采用三路合并算法生成合并结果。该算法至少在...

车子(chezi) 5476
上一篇: 「数组」希尔排序 / 区间增量优化(C++)
下一篇: 「数组」逆序对 / LeetCode LCR 170(C++)
Daking-
博客等级 码龄3年 912粉丝 70原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值