链表排序c++代码_[链表面试算法](一) 链表的删除-相关题型总结(6题)

在数据结构的最高层抽象里,只有两种结构,数组和链表。这两种结构,是所有其他数据结构实现的基础。队列和栈,可以用链表和数组来实现。图,可以用邻接表和邻接矩阵来实现,其中,邻接表就是链表,邻接矩阵就是数组。树,用数组实现,可以实现堆,用链表实现,可以实现二叉树,AVL树等等。

所以,链表的操作是掌握数据结构最基础的能力。一切数据结构的操作,无非就是遍历+增删查改。由于每一种数据结构有不同的特性,比如,数组结构,不需要存储指针,而链表结构需要存储指针。数据结构的增删查改,就是在这些特性的基础之上来完成的。

关于链表面试算法的第一块,主要来学习链表这种数据结构,是如何来实现删除节点的。

常见的删除节点题目有:

  1. 删除链表中的节点_leetcode273
  2. 移除链表元素_leetcode203
  3. 删除链表的倒数第N个节点_leetcode19
  4. 删除排序链表中的重复元素_leetcode83
  5. 删除排序链表中的重复元素 II_leetcode82

1.删除链表中的节点

思路分析:

在链表中,删除一个节点node的常见方法是,
找到该节点的前驱节点,修改节点的next指针,使其指向node的下一个节点。

02dd236e97e14b71868213be0d07e5fb.png
时间复杂度为O(1)的方法:
把将要删除的node节点的值,替换为它的后继节点,然后删除它之后的节点即可。
但是,这种方法需要保证,被删除的节点不是链表末尾。
若是末尾,则只能通过找到前序节点的方法来实现删除。

ef85f397329039f605f0f832cab629e2.png

被删除节点不为尾结点情况下,代码演示如下:

class Solution {public void deleteNode(ListNode toBeDeleted) { toBeDeleted.val = toBeDeleted.next.val;toBeDeleted.next = toBeDeleted.next.next;}
}

被删除节点可能为尾结点情况下,代码演示如下:

public static ListNode deleteNode(ListNode head,ListNode toBeDeleted){if(head==null || toBedeleted == null){return head;}// 若被删除节点为尾结点,则遍历链表,找到其前驱节点if(toBeDeleted.next == null){ListNode curr = head;while(curr.next!=toBeDeleted){curr = curr.next;}curr.next = null;//直接删除为节点}else{toBeDeleted.value = toBeDeleted.next.value;// 待删除的结点的下一个指向原先待删除引号的下下个结点,即将待删除的下一个结点删除  toBeDeleted.next = toBeDeleted.next.next;}//return head;}

2.移除链表元素

744ea73e7dc7da1a06154f2b0990d454.png

思路:

方法:哑结点+双指针
步骤:设置前驱指针pre和工作指针cur来遍历数组,若发现目标值,则删除,否则,一起向前。

代码:

class Solution {public ListNode removeElements(ListNode head, int val) {ListNode dummy = new ListNode(-1);dummy.next = head;ListNode pre = dummy;ListNode cur = head;while(cur!=null){if(cur.val==val){pre.next = cur.next;cur = cur.next;}else{pre=cur;cur=cur.next;}}return dummy.next;       }
}

3.删除链表的倒数第N个节点

思路:

使用两个指针,首先,p1指向头结点,p2指向第n+1个节点。
然后,p1,p2两个指针同时向后移动。当p2指向尾节点时,p1指向的便是倒数第n+1个节点。
倒数第n+1个节点为倒数第n个节点的前驱。
难点:如何定位到第n个节点,这个需要特别注意。使用for循环定位比使用while循环定位更易理解。巧用哑结点,避免空指针等多种情况的讨论。  

不使用哑结点来进行运算时,代码如下:

public ListNode removeNthFromEnd(ListNode head, int n) {ListNode p=head;int len=0;while (p!=null){p=p.next;++len;}if(len<n)return null;if(len==n) return head.next;ListNode p1=head,p2=head;// p1指向第一个数,需要移动n步,才能指向第n+1个数,此时p1与p2的距离为n。for(int i=1;i<=n;i++){p1=p1.next;}while (p1.next!=null){p1=p1.next;p2=p2.next;}p2.next=p2.next.next;return head;  }

使用哑结点的方式代码如下:

class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dummy = new ListNode(-1);dummy.next = head;ListNode p1 = dummy;// p1实际上为被删除节点的前驱节点,即倒数第n+1个节点。ListNode p2 = dummy;// p2移动n步,指向原链表中的第n个节点,此时p1与p2之间的距离为n.for(int i=1;i<=n;i++){p2 = p2.next;}// p1,p2同时向后移,当p2指向尾节点时,p1指向倒数第n+1个节点while(p2.next!=null){p1=p1.next;p2=p2.next;}p1.next = p1.next.next;return dummy.next;}
}

4. 删除排序链表中的重复元素

题目:

ee3bc17ec183b091370393bfbced5cb2.png

注意事项:

在链表题中,需要注意的是操作链表的结点指针,一定要做非空检查,避免报空指针异常。

思路:

因为输入的列表已排序,
因此我们可以通过将结点的值与它之后的结点进行比较来确定它是否为重复结点。
如果它是重复的,我们更改当前结点的 next 指针,以便它跳过下一个结点并直接指向下一个结点之后的结点。

代码如下:

class Solution {public ListNode deleteDuplicates(ListNode head) {ListNode cur = head;while(cur!=null && cur.next !=null){if(cur.val==cur.next.val){cur.next = cur.next.next;}else{cur = cur.next;}}return head;}
}

5. 删除排序链表中的重复元素 II

题目:

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现的数字。

df571b58a7e56ec80adacb732c6812b6.png

思路:

和上一题相比,需要在代码中实现去重操作。
哑结点+双指针法。
哑结点用于记录不重复数字的头,
p1指向不重复数字的最后一位,p2作为工作指针,向前扫描。
去重的判断条件(p2!=null && p2.next!=null && p2.val !=p2.next.val)

代码如下:

class Solution {public ListNode deleteDuplicates(ListNode head) {ListNode dumpy = new ListNode(-1);ListNode p1 = dumpy;ListNode p2 = head;while(p2!=null){if(p2!=null && p2.next!=null && p2.val == p2.next.val){// 若重复,则实现去重操作int temp = p2.val;while(p2!=null&&p2.val==temp){p2=p2.next;// 去重操作}}else{// 否则将不重复节点加入到新链表中。ListNode next = p2.next;p2.next = null; // p2和原来节点断开p1.next=p2;  // 将阉割后的p2节点加到p1上p1 = p2;p2 = next;}}return dumpy.next;}
}

总结

从上述的五道链表删除题可以看出,这种题目常见的技巧是使用哑结点+双指针来做,可以避免很多非空的判断,使得代码健壮且简洁。

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

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

相关文章

c语言如何空格键返回主菜单,C语言中scanf函数与空格回车的用法说明

众所周知&#xff0c;C语言中的scanf函数的作用是从标准输入设备(通常是键盘)读取输入值&#xff0c;并存储到参数列表中指针所指向的内存单元。下面从几个方面说一下一些稍微细节的东西。下面的实验都在vc6.0中通过。1、scanf的返回值scanf通常返回的是成功赋值(从标准输入设备…

Linear_algebra_03_矩阵

1. 矩阵的线性运算&#xff1a; 2.1 矩阵的乘法&#xff1a;Xik * Ykj Zij 2.2 矩阵乘法性质&#xff1a; 3.1 矩阵的幂次方运算 3.2 矩阵转置的运算律 3.3 方阵运算 4 分块矩阵的运算 5. 矩阵的初等变换 5.1 单位矩阵I经过一次初等变换所得到的矩阵称为初等矩阵. 5.2 初等矩…

js转json工具_菜鸟丨Egert3D微信小游戏发布与Unity工具使用

本次教程将会为大家介绍Egret3D工具导出Unity场景对象的使用&#xff0c;以及发布微信小游戏流程。让大家对Egret 3D有更加熟悉的了解。需求工具&#xff1a;1、Unity场景导出插件&#xff1b;2、微信开发者工具。导出插件的使用一、打开需要导出的Unity场景&#xff0c;并且把…

OI杂记

从今天开始记录一下为数不多天的OI历程 8.25 上 今天举行了难得的五校联考&#xff0c;模拟noip&#xff0c;题目的解压密码竟然是$aKnoIp2o18$&#xff0c;对你没有看错&#xff01;&#xff01;&#xff01; 7:50老师&#xff1f;啊啊啊啊&#xff0c;收不到题目啊&#xff0…

Java,Steam控制器和我

您是否想过是否可以将现有的东西用于新的东西&#xff1f; 我看了一些所谓的“蒸汽控制器”&#xff08;从现在开始为SC&#xff09;的镜头&#xff0c;并看着我的游戏手柄。 问我自己是否有可能以类似蒸汽的方式使用它&#xff0c;我找到了一些Java库并创建了一个项目&#xf…

unknown column in field list_tf.feature_column的特征处理探究

1. 背景tf.estimator是tensorflow的一个高级API接口&#xff0c;它最大的特点在于兼容分布式和单机两种场景&#xff0c;工程师可以在同一套代码结构下即实现单机训练也可以实现分布式训练&#xff0c;正是因为这样的特点&#xff0c;目前包括阿里在内的很多公司都在使用这一接…

pytorch如何定义损失函数_对比PyTorch和TensorFlow的自动差异和动态模型

使用自定义模型类从头开始训练线性回归&#xff0c;比较PyTorch 1.x和TensorFlow 2.x之间的自动差异和动态模型子类化方法&#xff0c;这篇简短的文章重点介绍如何在PyTorch 1.x和TensorFlow 2.x中分别使用带有模块/模型API的动态子类化模型&#xff0c;以及这些框架在训练循环…

Gradle命令行便利

在我的《用Gradle构建Java的gradle tasks 》一文中&#xff0c;我简要地提到了使用Gradle的“ gradle tasks ”命令来查看特定Gradle构建的可用任务。 在这篇文章中&#xff0c;我将对这一简短提及进行更多的扩展&#xff0c;并查看一些相关的Gradle命令行便利。 Gradle可以轻松…

java封装实现Excel建表读写操作

对 Excel 进行读写操作是生产环境下常见的业务&#xff0c;网上搜索的实现方式都是基于POI和JXL第三方框架&#xff0c;但都不是很全面。小编由于这两天刚好需要用到&#xff0c;于是就参考手写了一个封装操作工具&#xff0c;基本涵盖了Excel表&#xff08;分有表头和无表头&a…

argmax函数_1.4 TensorFlow2.1常用函数

1.4 TF常用函数tf.cast(tensor,dtypedatatype)可以进行强制类型转换。tf.reduce_min(tensor)和tf.reduce_max(tensor)将计算出张量中所有元素的最大值和最小值。import tensorflow as tfx1 tf.constant([1., 2., 3.], dtypetf.float64)print("x1:", x1)x2 tf.cast(…

设计模式---数据结构模式之迭代器模式(Iterate)

一&#xff1a;概念 迭代模式是行为模式之一&#xff0c;它把对容器中包含的内部对象的访问委让给外部类&#xff0c;使用Iterator&#xff08;遍历&#xff09;按顺序进行遍历访问的设计模式。 在应用Iterator模式之前&#xff0c;首先应该明白Iterator模式用来解决什么问题。…

识别Gradle约定

通过约定进行配置具有许多优点&#xff0c;尤其是在简洁方面&#xff0c;因为开发人员不需要显式配置通过约定隐式配置的内容。 但是&#xff0c;在利用约定进行配置时&#xff0c;需要了解约定。 这些约定可能已经记录在案&#xff0c;但是当我可以编程方式确定约定时&#xf…

高校c语言题库,C语言-中国大学mooc-题库零氪

第1 周 程序设计与C语言简介1.1 程序设计基础随堂测验1、计算机只能处理由人们编写的、解决某些问题的、事先存储在计算机存储器中的二进制指令序列。第1周单元测验1、通常把高级语言源程序翻译成目标程序的程序称为( )。A、编辑程序B、解释程序C、汇编程序D、编译程序2、一个算…

场景法设计测试用例

在面向对象的软件开发中&#xff0c;事件触发机制是编程中经常遇到的。 &#xff08;一&#xff09;场景法原理 现在的软件几乎都是用事件触发来控制流程的。像GUI软件、游戏等。事件触发时的情景形成了场景&#xff0c;而同一事件不同的触发顺序和处理结果就形成了事件流。这种…

python中range函数是什么意思_python里range是什么

python range() 函数可创建一个整数列表&#xff0c;一般用在 for 循环中。函数语法&#xff08;推荐学习&#xff1a;Python视频教程&#xff09;range(start, stop[, step]) 参数说明&#xff1a; start: 计数从 start 开始。默认是从 0 开始。例如range&#xff08;5&#x…

android高德地图搜索地址,地点/周边搜索-Android平台-开发指南-高德地图车机版 | 高德地图API...

关键字搜索第三方通过该接口可传入关键字信息给auto&#xff0c;调起auto执行关键字搜索并跳转到搜索结果展现界面&#xff0c;官网版本都可支持参数说明参数说明是否必填类型ActionAUTONAVI_STANDARD_BROADCAST_RECV是stringKEY_TYPE协议ID:10036是intSOURCE_APP第三方应用名称…

Luogu 3626 [APIO2009]会议中心

很优美的解法。 推荐大佬博客 如果没有保证字典序最小这一个要求&#xff0c;这题就是一个水题了&#xff0c;但是要保证字典序最小&#xff0c;然后我就不会了…… 如果一条线段能放入一个区间$[l, r]$并且不影响最优答案&#xff0c;那么对于这条线段$[l, r]$&#xff0c;设$…

python编程求导数_面向对象编程 —— java实现函数求导

首先声明一点&#xff0c;本文主要介绍的是面向对象&#xff08;OO&#xff09;的思想&#xff0c;顺便谈下函数式编程&#xff0c;而不是教你如何准确地、科学地用java求出函数在一点的导数。 一、引子 defd(f) :defcalc(x) : dx 0.000001 #表示无穷小的Δx return (f(xdx) - …

BZOJ5093图的价值(斯特林数)

题目描述 “简单无向图”是指无重边、无自环的无向图&#xff08;不一定连通&#xff09;。一个带标号的图的价值定义为每个点度数的k次方的和。给定n和k&#xff0c;请计算所有n个点的带标号的简单无向图的价值之和。因为答案很大&#xff0c;请对998244353取模输出。题解因为…

python程序写诗_用Python作诗,生活仍有诗和远方

原标题&#xff1a;用Python作诗&#xff0c;生活仍有诗和远方 报 名 来源&#xff1a;TheodoreXu链接&#xff1a; https://segmentfault.com/a/1190000013154329 常听说&#xff0c;现在的代码&#xff0c;就和唐朝的诗一样重要。 可对我们来说&#xff0c;写几行代码没什么&…