LeetCode.26,27,88三题-双指针的运用

news/2024/10/31 1:35:13/

本文将对3道解决方法类似的题目进行逐一分析,这三道题目分别是:

LeetCode.26 删除有序数组中的重复项

LeetCode.27 移除元素

LeetCode.88 合并两个有序数组

1. LeetCode.27 移除元素:

题目内容如下:

 假设一个数组nums为:

nums = [0,1,2,2,3,0,4,2]

元素val = 2.

按照题目的要求,需要移除数组nums中所有等于2的元素。对于此题的解析,文章提供三种参考思路

1.在之前处理顺序表中删除元素的问题时,采用的方法是将目标元素后面的元素全部向前覆盖一位。但是,这种处理方法的时间复杂度为O(N^2)过于缓慢。

2.创建一个指针和一个新的数组,遍历整个数组,在便利的过程中。若被遍历的元素大小不等于val时,将此元素复制到新开辟的数组中。当被遍历的元素大小等于val时,不复制并且将指针指向下一个元素。此方法的时间复杂度为O(N),相对于方法1,大幅度降低了程序执行所用的时间。但是,该方法因为新创建了一个数组。空间复杂度为O(N),不符合题目中的要求。

3. 虽然方法2不满足题目的要求,但是可以通过方法2的思路来延伸出方法3,也就是文章题目中提到的双指针法

对于本题,双指针法的具体用法如下:

1.创建两个指针,这里创建的指针分别命名为src,dst。最开始,两个指针都指向数组首元素的下标,即:

 对于本题中创建的两个指针的动作,总结下来就是:将数组中src位置上不等于val的元素放置到dst中。

当两个指针所对应的元素相等且不等于val时,都指向下一个元素。

当指针src对应的值等于val时,指针src指向下一个位置,dst不移动

当两个指针对应的元素不同且不等于val时,将指针src对应的元素赋值到dst位置。并且都向前移动一位。

用图片表示下列过程,即:

1.

 2.

此时, 指针src对应的值等于val。所以指针dst不动,指针src继续向后移动:

此时,指针 src对应的值不等于dst,并且不等于val。所以,进行赋值操作:

 再次向后移动,还会重复上面的动作:

当 src遍历整个数组后,数组中内容如下图所示:

上述过程对应的代码为:

int removeElement(int* nums, int numsSize, int val){int dst = 0;int src = 0;while( src < numsSize){if( nums[src] != val){nums[dst++] = nums[src++];}else{src++;}}return dst;}

 2. LeetCode.88 合并两个有序数组:

题目如下:


 

给出的示例如下:
 

 用图片表示上面给出的示例,即:

 对于这道题的解法,依旧采用双指针的思想,对于每一个数组均创建一个指针。但是,如果再次采用上面从头到尾进行遍历的方法,如果再某处需要插入元素,则还是会出现顺序表中插入元素出现的问题,即:每插入一个元素,都需要将后面的元素整体后移动一位。所以对于此题。最好采用从后向前,从大到小的顺序进行遍历。并且,将第一个数组中最大的元素与第二个数组中的元素分别进行比较。较大的则插入到第一个数组中后面的区域,将上述过程用图片演示,即:

 上面的情况中,是第二个数组元素全部遍历完成时,第一个数组中的元素没有完成遍历。但是对于下面的情况,即:第一个数组完成遍历时,第二个数组并没有完成遍历:

用图片表示上述数组中元素的变化情况:

 ​​

 

 最后的结果如上图所示: 第二个数组中的元素2并没有插入到第一个数组中。并且第一个数组已经遍历完成。而第二个数组没有遍历完成。

总结上述过程,为了方便陈述,将第一个数组命名为nums1,将第二个数组命名为nums2

nums1创建的指针命名为dst,为nums2创建的指针命名为src

从后向前对两个数组同时遍历,

当满足src对应的元素>dst对应的元素时,将src对应的元素在nums1中进行一个尾插操作。并且两个指针均指向前一个元素。

当不满足上述关系时,将dst对应的元素在nums1在前面插入元素的基础上进行一个尾插操作。并将dst指向前一个元素。

nums2遍历完成时。标志着程序运行完成。当nums1遍历完成但是nums2没有完成遍历时。将nums2剩余的元素在nums1中进行插入。

用代码表示上述过程:

首先,题目中已给的参数分别是:

m表示 nums1中非0的元素。n表示nums2中的元素。为了方便表示,用end1,end2表示上面的参数。end表示nums1中加上0元素的总长度。

代码如下:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){int end1 = m - 1; int end2 = n -1;int end = m + n -1;while( end1 >= 0 && end2 >= 0){if( nums1[end1] > nums2[end2]){nums1[end--] = nums1[end1--];}else{nums1[end--] = nums2[end2--];}}while( end2 >= 0){nums1[end--] = nums2[end2--];}}

3. LeetCode. 26 删除有序数组中的重复项:

题目如下:

 示例如下:

依旧采用双指针的方法来结局问题。创建两个指针分别为src,dst

从上面的题目要求可知。题目涉及到对于数组中元素的更改。所以,创建的两个指针在开头可以处于相同位置,也可以处于不同位置。为了方便演示,这里给出不同位置的情况,例如下面图片所示的数组:

 

 因为要保证数组中元素不能重复,所以,需要将后面的元素覆盖到前面元素的位置。所以,需要一个指针取读取后一位的元素,并且与前一位的元素进行对比。此时如果后一位元素与本位元素相同。则src指向后一个元素:

 此时,两个指针指向的元素不同,所以,先让dst指向后一位元素,再将src中的元素赋值给此时的dst,再src+1,此时两个指针指向的元素相同,所以一直src+1,直到:

 重复上面所说的步骤,即:

 

 按照前面说的规则,最后的效果为

 

通过图片不难发现,程序结束的标志就是当指针src <= 数组中元素个数-1时(或者src <数组中元素个数时)。

总结上述过程,可以分为三个要点:

1. src < 数组中元素个数时,程序结束

2.src指向的值=dst时,src指向后面的元素。dst不变。

3. src指向的值不等于dst时,先将dst+1,再将src+1指向的值赋值到dst,最后src+1.

用代码表示,即:

int removeDuplicates(int* nums, int numsSize){int dst = 0;int src = 1;while( src < numsSize){if( nums[src] == nums[dst]){src++;}else{dst++;nums[dst] = nums[src];src++;}}return dst+1;}

 


 

 


http://www.ppmy.cn/news/1026917.html

相关文章

SSH隧道搭建简单使用

参考&#xff1a; https://www.zsythink.net/archives/2450 https://luckyfuture.top/ssh-tunnel#SSH%E9%9A%A7%E9%81%93 https://zhuanlan.zhihu.com/p/561589204?utm_id0 SSH隧道&#xff08;搭建SSH隧道绕过防火墙&#xff09;&#xff1a; ssh命令除了登陆外还有代理转发…

uniapp 获取 view 的宽度、高度以及上下左右左边界位置

<view class"cont-box"></view> /* 获取节点信息的对象 */ getElementRect() {const query uni.createSelectorQuery().in(this);query.select(".cont-box").boundingClientRect(res > {console.log(res);console.log(res.height); // 10…

accumulate函数的简单应用

accumulate函数是C numeric库中的一个函数&#xff0c;主要用来对指定范围内元素求和&#xff0c;但也自行指定一些其他操作&#xff0c;如范围内所有元素相乘、相除等。 使用前需要引用头文件&#xff1a; #include <numeric>函数共有四个参数&#xff0c;其中前三个为…

【第一阶段】kotlin中反引号中的函数名特点

在kotlin中可以直接中文定义函数&#xff0c;使用反引号进行调用 eg: fun main() {2023年8月9日定义的函数(5) }private fun 2023年8月9日定义的函数(num:Int){println("反引号的用法$num") }执行结果 在Java中is,in可以定义方法&#xff0c;但是在kotlin中is,in是…

GEE学习04-

0 回顾 之前学习的内容可以概括为&#xff1a; conda activate gee cd /d e:/geelearn jupyter lab可以在prompt中chrlc停止当前打开的jupyter lab. import ee #ee.Authenticate() import geemap geemap.set_proxy(port 1080) map geemap.Map() map1、视频课学习 之后跟着…

VMware 16 Pro将电脑里的文件移动到虚拟机中【附带可能出现的问题和解决】

VMware 16 Pro将电脑里的文件移动到虚拟机中 1.使用VM tools 打开VM ware会出现下面的&#xff0c;直接点击安装。 点击下一步 选哪个都行 之后会重启虚拟机&#xff0c;然后就可以使用了。 我没有程序可以打开压缩包&#xff0c;显示我的虚拟机网络没法用&#xff0c;点击…

vue全局组件自动注册直接使用,无需单独先引用注册再使用

目录结构&#xff1a; 本案例是在根目录下components文件夹测试的&#xff0c;文件位置项目内任意&#xff0c;确保在main.js挂载路径正确即可 1、新建文件夹&#xff08;名字随意&#xff09;zxy_components (放自己组件的地方) 2、在zxy_components文件夹下 &#xff01;新建…

第7章 用函数实现模块化程序设计

7.1 为什么要用函数 在设计一个较大的程序时&#xff0c;往往把它分为若干个程序模块&#xff0c;每一个模块包括一个或多个函数&#xff0c;每个函数实现一个特定的功能。一个C程序可由一个主函数和若干个其他函数构成。由主函数调用其他函数&#xff0c;其他函数也可以互相调…