【初阶数据结构】——双“指针”求解数组常见问题

news2025/1/11 2:57:09

文章目录

    • 前言
    • 题目1:移除元素
      • 思路1:暴力求解
      • 思路2:时间换空间
      • 思路3:双指针原地删除(解法2的再优化)
        • 思路分析
        • 代码实现
    • 题目2:删除有序数组中的重复项
      • 思路:双指针
      • 代码实现
    • 题目3:合并两个有序数组
      • 常规合并方法
      • 题目分析
      • 思路:三指针
      • 代码实现

前言

这篇文章,我们一起来看几道数组相关的面试题。
在这里插入图片描述
每道题目,我们给出的解题思路可能都不止一种,我们要不断分析讨论,找出最优的解题思路来实现
一起来看看吧!!!

题目1:移除元素

题目链接放在这里,供大家练习:链接: link
先来看一下题目吧:
在这里插入图片描述
题目是什么意思呢?

其实就是给我们一个数组,还有一个值val,我们要删除这个数组中所有值和val相等的元素,然后返回删除之后的新数组的长度。

那怎么解决呢?接下来我们一起来分析一下:

思路1:暴力求解

思路1就是暴力求解,这也是我们可能最先会想到的一个方法:从头到尾找一个删除一个。

怎么做呢?

从数组的第一个元素开始,向后遍历,如何当前元素的值等于val的值,就删除
怎么删呢?
将后面的元素,依次向前移动,将要删除的元素覆盖掉。后面也是如此,直至将数组中所有值等于val的元素都删除掉,就完成了。

那大家思考一下,这个方法好不好?

肯定是不太好的,如果给的数组中有大部分元素的值都等于val,比如像这样:
在这里插入图片描述
val的值是2,数组中所有等于2的元素,都要删除,每次删除都要挪动数据,等于val的元素越多,挪动的次数就越多,有些数据就会被不断地,重复的挪动,这样它的时间复杂度其实可以认为是O(N^2),效率就可能会比较低。
在这里插入图片描述

那这种方法我们就不实现了,我们再思考思考有没有更优的解法。

思路2:时间换空间

第一中解法暴力求解,它的时间复杂度太大了,那有没有更好的方法呢?

这里提供一种时间换空间的解法。

具体思路是这样的:

我们再额外创建一个数组,假设命名为tmp,然后对原数组进行遍历,如果当前元素不等于val,就把他拷贝到tmp数组中,如果等于val,不做处理,这样遍历结束,tmp数组中放的就是删除之后的元素,然后我们把tmp中的元素再拷贝回原数组,tmp的大小就是要返回的新长度。
在这里插入图片描述
那这种思路,它的**时间复杂度就是就是O(N)**了,与第一种方法的O(N^2)相比,就好很多了。

但它的的缺点在于:

我们又额外开辟了一个数组,该数组的大小与原数组等大,因此它的空间复杂度也是O(N)。这是他不好的地方。
而且呢,题目也要求:
在这里插入图片描述
所以,这还没有完,我们要继续优化,找出一个即效率高,还不用开辟额外空间的算法。

那有没有这样的解法呢?

当然有,其实我们对解法2再稍做优化,就行了。

思路3:双指针原地删除(解法2的再优化)

其实思路还是2的思路,只不过这次我们不再另外开辟一个新的数组了。

那要怎么搞呢?

思路分析

这里我们定义两个变量作为两个指针(注意这里说的指针只是一个形象化的称谓,不是用来存储地址的指针变量),开始它们都指向0下标的位置。
在这里插入图片描述

然后呢:

我们src指向的元素和val比较,如果不相等,就把src指向的元素赋值给dest指向的元素,即nums[dest]=nums[src],然后让dest和src都++。
然后再让src指向的元素和val比较,不相等继续上述操作,如果相等了,我们只让src++往后走,dest不动,然后再让src指向的元素和val比较,看是否等于val。
直至遍历完整个数组。

在这里插入图片描述

在这里插入图片描述

代码实现

那现在思路理清了,图也画出来了,接下来写代码就很简单了:

直接上代码:

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

在这里插入图片描述

题目2:删除有序数组中的重复项

链接分享给大家:链接: link
一起看一下题:
在这里插入图片描述

这道题呢,其实就是让我们去重,数组中有些值重复出现,我们要让所有的元素都只出现一次,最终还是返回新数组长度。

这道题怎么做呢?

比较简单的一种方法还是利用双指针来解决。

思路:双指针

那这个题该如何利用双指针求解呢?

首先,还是定义两个变量作为指针,初始都指向下标为0位置。
在这里插入图片描述

如果两指针指向的元素相等,我们只让 src++往后走,过滤掉重复值。
在这里插入图片描述

如果不再相等,先让dest++,让后把src指向的元素赋值给dest指向的元素,然后再让src++。
在这里插入图片描述

然后再判断两指针指向的元素是否相等,重复上述操作,直至src遍历完数组。
在这里插入图片描述
最终dest+1就是去重后的数组长度。

代码实现

上代码:

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

在这里插入图片描述

题目3:合并两个有序数组

链接: link
在这里插入图片描述

常规合并方法

首先我们思考一下,如果给我们两个非递减的数组,我们如何去合并它们。

其实用双指针的方法还可以搞定,举个例子:

假如现在有这样两个数组:
在这里插入图片描述

如何合并?

两个指针分别指向两数组第一个元素,再开辟一个新数组,对他们进行比较,依次取较小的那个元素放到新数组中,如果相等,任选一个放入。
在这里插入图片描述

但是,对于这个题,这种方法可行吗?

显然是不可行的。

题目分析

为什么不可行呢?

我们来看这道题:
在这里插入图片描述
它给我们两个按 非递减顺序 排列的整数数组 nums1 和 nums2,确定是要求我们,但是要求我们把合并后的数组放到nums1 中
也就是说,nums1 提前把空间开好了,已经足够放得下合并之后的整个数组了,不需要我们再额外开辟新数组了。

那上面那种方法显然就不适用了。

那这种情况我们应该怎么搞呢?

就拿题中这个例子来看:在这里插入图片描述
如果我们还像上面那样从前往后两两比较大小,还可以吗?
如果nums2的的第一个元素就比nums1的小,那题目要求放到
nums1里,这样是不是就把nums2的第一个元素覆盖掉了啊。

所以这样搞不行。

那应该怎么办呢?

在这里插入图片描述
我们知道,nums1已经提前开好了多余的空间,这些空间在哪里啊,是在nums1有效数据的后面

思路:三指针

所以我们怎么做比较好?

是不是从后往前倒着比较啊。
怎么比?
要取出两者中较大的元素放到后面,后面的数据我们覆盖掉是没问题的。

那接下来我来画图带大家再梳理一下思路:

这里需要我们再增加一个指针。
在这里插入图片描述
指针i1,i2分别指向数组nums1和nums2的最后一个元素,注意nums1是有效数据的最后一个,然后加一个dest指向nums1的最后一个位置。

然后开始比较:

i1,i2指向的元素哪个大,就把该元素赋值给dest指向的元素,然后dest和对应的i1或i2向前移动一个位置,继续比较。
在这里插入图片描述
相等的话,我们随便给哪一个都行
我这里就选择把i1指向的值给dest。

在这里插入图片描述

这一步的代码就是这样:

在这里插入图片描述

然后继续走:

走到这个位置我们发现
在这里插入图片描述
i2就走完了,遍历结束了,那此时是不是就完成了啊
在这里插入图片描述
这就是最终的状态了。

所以:

如果是i2先走完,i2走完就结束了,完成了。因为这些元素本来就在nums1中,不需要动了。

那也有可能是i1先走完啊,i1先走完是不是也直接结束了呢?我们来分析一下:

看这种情况:
在这里插入图片描述
还是按上面的方法依次进行比较。

但是这次我们会发现:

在这里插入图片描述
这次是i1先走完,但是这样结束了吗。
还没有,
我们需要把nums2中剩下的元素再拷贝到nums1前面的位置。

所以要注意:

如果是i1先走完,我们还需要继续处理,把nums2中剩余的元素放到nums1中。
在这里插入图片描述

代码实现

所以最终代码应该是这样的

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

再简单解释一下,相信大家就能很好的理解了:

首先说一下,题目里给的参数有些冗余
在这里插入图片描述
nums1Size和nums2Size其实不要也可以,因为nums1Size就是m+n,nums2Size就是n。

然后代码也简单提一下:

在这里插入图片描述
所以最终的代码就是这样。
在这里插入图片描述

好了,以上就是几个数组相关面试题的讲解,欢迎大家指正!!!
在这里插入图片描述

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

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

相关文章

【JavaScript】BOM 学习总结

基础知识&#xff1a; 获取浏览器窗口的尺寸&#xff1a; innerHeight&#xff1a;获取高度 innerWidth&#xff1a;获取宽度 跳转与刷新 location.href location.reload() body><button id"btn">跳转到下一个页面</button><button id"btn…

Java实现文件操作

目录 一、文件概述 二、常见文件操作 1、获取文件路径 2、判断文件存在以及判断类型 3、文件的创建与删除 4、展示文件夹的文件 5、创建文件夹 三、用数据流来读取文件内容 1、操作字节流文件 a、读取字节流文件 b、写字节流文件 2、操作字符流对象 a、读取…

C++ · 入门 · 03 | 函数重载

啊我摔倒了..有没有人扶我起来学习.... 目录前言函数重载1.1 函数重载概念1.2 函数重载的意义1.3 C支持函数重载的原理--名字修饰(name Mangling)1.4 返回值不同能否构成函数重载?前言 自然语言中&#xff0c;一个词可以有多重含义&#xff0c;人们可以通过上下文来判断该词真…

小米 2021 秋招面试总结

岗位:嵌入式软件工程师(相机驱动岗) 面试时间: 40 分钟 薪资: 28w+ 面试过程 面试官上来先来了一段他自己的自我介绍,流程还是比较规范的。 1、请进行一个简单的自我介绍(2分钟) 2、C语言全局变量可否定义在头文件中? 回答:不能,并且这不是一个好的习惯。 3…

【自学C++】C++输出cout

C输出cout C输出cout教程 在 C 语言 中我们需要输出一个 变量&#xff0c;可以使用 printf。printf 函数 在输出时&#xff0c;我们必须要指定输出的数据类型对应的格式化符&#xff0c;挺不方便。 在 C 中&#xff0c;我们要输出变量&#xff0c;直接使用 std 命名空间中的…

国科大抢课避坑+选课指南+教务系统操作

博客园&#xff1a; https://www.cnblogs.com/phoenixash/p/13669461.html 9月12日12&#xff1a;30&#xff0c;本菜鸡终于经历了国科大传说中的抢课大战&#xff0c;虽然自己之前准备的较多&#xff0c;但还是在抢课的时候掉进了不少坑里&#xff0c;趁现在还记忆犹新&#x…

【pandas】教程:10-文本数据的操作

Pandas 文本数据的操作 本节使用的数据为 data/titanic.csv&#xff0c;链接为 pandas案例和教程所使用的数据-机器学习文档类资源-CSDN文库 读入数据 import pandas as pd titanic pd.read_csv("data/titanic.csv")PassengerId Survived Pclass \ 0 …

指针进阶(2)

Tips 1. 2. 3. 碰到地址就等价于指针变量&#xff0c;里面存放着该地址的指针变量 4. 数组指针是存放数组的地址&#xff0c;指向的是一个数组&#xff1b;函数指针存放的是函数的地址&#xff0c;指向的是一个函数。 5. 地址就是指针&#xff0c;地址就是指针 6. 数…

LeetCode 138. 复制带随机指针的链表(C++)

思路&#xff1a; 用哈希表实现&#xff0c;创建一个哈希表来对应原链表中的每一个节点&#xff0c;这样也可以将原链表中的所有结点的next和random关系映射到哈希表复制链表中。 原题链接&#xff1a;https://leetcode.cn/problems/copy-list-with-random-pointer/description…

1658. 将 x 减到 0 的最小操作数

解法一&#xff1a;双指针 首先&#xff0c;每次操作可以移除数组 nums 最左边或最右边的元素&#xff0c;那么相当于求出l和rl和rl和r使得[0,l][r,n−1][0, l][r,n-1][0,l][r,n−1]之间所有元素之和等于xxx,并且元素个数最少。我们可以通过双重循环枚举l和r变量l和r变量l和r变…

马哥架构第1周课程作业

马哥架构第1周课程作业一. 画图解释一次web请求的过程。涉及tcp/ip, dns, nginx&#xff0c;wsgi。二. 编译安装nginx, 详细解读常用参数。三. 基于nginx完成动静分离部署 lamp。php到后端php-fpm, static/ 在nginx本地。3.1 配置 nginx 实现反向代理的动静分离3.2 准备后端 ht…

equals和==的区别

目录 1.基本数据类型和引用数据类型的说明 2. 3.equals 1.基本数据类型和引用数据类型的说明 基本数据类型&#xff1a;byte&#xff0c;short&#xff0c;int&#xff0c;long&#xff0c;float&#xff0c;double&#xff0c;char&#xff0c;boolean。 对应的默认值&…

2-4进程管理-死锁

文章目录一.死锁的概念二.死锁的处理策略1.死锁预防&#xff1a;破坏必要条件&#xff0c;让死锁无法发生2.避免死锁&#xff1a;在动态分配资源的过程中&#xff0c;用一些算法防止系统进入不安全状态&#xff08;1&#xff09;银行家算法&#xff08;2&#xff09;系统安全状…

Java if else分支结构精讲

Java 支持两种选择语句&#xff1a;if 语句和 switch 语句。其中 if 语句使用布尔表达式或布尔值作为分支条件来进行分支控制&#xff0c;而 switch 语句则用于对多个整型值进行匹配&#xff0c;从而实现分支控制。这些语句允许你只有在程序运行时才能知道其状态的情况下&#…

2022:不恋过往,不畏将来

一、开篇 少年有山海&#xff0c;踏过皆繁华。岁月不居&#xff0c;时节如流&#xff0c;时间在指尖悄悄流逝&#xff0c;人生即将翻开新的一年的篇章。2022年&#xff0c;注定是一个不平凡的年份&#xff0c;这一年&#xff0c;我们从关心世界到关心国家&#xff0c;最后关心自…

2023年12306购票平台自动化购票二|解决车次查找与预定

目录 一、说明 1.1、背景 1.2、说明 二、步骤 2.1、点击去购票 2.2、在搜索框中输入车次信息 2.3、点击查找 2.4、出现车次信息&#xff0c;进行筛选&#xff0c;如果有票则点击计入预定车票界面 三、结果 四、小节 一、说明 1.1、背景 接上文&#xff0c;春运抢不到…

适用于 Windows 的 5 大 PDF 编辑器

“如何在 Windows 7/8/10/11 上编辑 PDF 文件&#xff1f;” “适用于 Windows 7/8/10/11的最佳 PDF 编辑器是什么&#xff1f;” 升级到 Windows 7/8/10/11 后&#xff0c;你会发现很多应用程序在新的 Windows 系统上无法运行&#xff0c;包括 PDF 编辑器。然而&#xff0c;一…

POJ 3070 Fibonacci

Time Limit: 1000MSMemory Limit: 65536KTotal Submissions: 30932Accepted: 20284 Description In the Fibonacci integer sequence, F0 0, F1 1, and Fn Fn − 1 Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are: 0, 1, 1, 2, 3,…

opencv源码之中值滤波medianBlur_SortNet解读

背景中值滤波&#xff0c;最大值滤波&#xff0c;最小值滤波属于排序滤波&#xff0c;常用于图像去噪处理。最大/小值滤波的处理比较好理解&#xff0c;就是逐个比较窗口内的每个数字&#xff0c;每次比较会根据所属任务保留最大值&#xff0c;或最小值。假设滑动窗口是3*3&…

固体物理分子模拟实验(二)MPI的安装

固体物理分子模拟实验&#xff08;二&#xff09;MPI的安装 文章目录固体物理分子模拟实验&#xff08;二&#xff09;MPI的安装前言一、MPI是什么&#xff1f;二、安装步骤&#xff08;Ubuntu22.04mpich-4.0.2&#xff09;1、下载mpich解压包2、安装前置组件3、文件配置&#…