单链表删除(Delete)或者去除(Remove)节点面试题总结
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76061004冷血之心的博客)
关于单链表反转的多种形式请参见本博文:
本文总结常见面试题中关于删除和去除节点的相关问题。题目如下:
1、给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted: delete
2、去除重复节点,保留一个即可
3、去除重复节点,将重复节点全部删除
4、删除具有指定val值的节点
5、删除倒数第N个节点
我们先来看看第一题:
(1)给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted: delete
思路:通过复制下一个节点的val值到要删除的节点,而把下一个节点删除,修改了next指针,实现了O( 1 )复杂度删除指定节点。(该题的假设是要删除的节点一定存在该链表中,否则O(1)不可能实现)
/**
* 给出一单链表头指针head和一节点指针toBeDeleted,O(1)时间复杂度删除节点tBeDeleted
* 对于删除节点,我们普通的思路就是让该节点的前一个节点指向该节点的下一个节点
* ,这种情况需要遍历找到该节点的前一个节点,时间复杂度为O(n)。对于链表,
* 链表中的每个节点结构都是一样的,所以我们可以把该节点的下一个节点的数据复制到该节点
* ,然后删除下一个节点即可。要注意最后一个节点的情况,这个时候只能用常见的方法来操作,先找到前一个节点,但总体的平均时间复杂度还是O(1)
*/
public static void delete(Node head, Node toDelete){
if(toDelete == null){
return;
}
if(toDelete.next != null){ // 要删除的是一个中间节点
toDelete.val = toDelete.next.val; // 将下一个节点的数据复制到本节点!
toDelete.next = toDelete.next.next;
}
else{ // 要删除的是最后一个节点!
if(head == toDelete){ // 链表中只有一个节点的情况
head = null;
}else{
Node node = head;
while(node.next != toDelete){ // 找到倒数第二个节点
node = node.next;
}
node.next = null;
}
}
}
第二题:
(2)、去除重复节点,保留一个即可
思路:该题最后返回的结果要求保留一个重复的节点,这就比较easy了,直接判断,跳过与当前节点重复的节点即可。
public class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head==null||head.next==null)
return head;
ListNode cur = head;
while(cur.next!=null){
if(cur.val==cur.next.val)
cur.next = cur.next.next;
else
cur = cur.next;
}
return head;
}
}
第三题:(Hard)
(3)、去除重复节点,将重复节点全部删除
思路:将重复节点全部删除,一个不留,这就是本题的难点所在,我们必须保存当前节点的前一个节点,因为我们不知道当前节点是否是重复节点。
还有一个难点,当开头就是重复元素时,我们需要调整head,这时候需要一些判断条件。
public class Solution {
public ListNode deleteDuplication(ListNode pHead){
if(pHead==null||pHead.next==null)
return pHead;
ListNode cur = pHead;
ListNode preNode = null;
while(cur!=null){
if(cur.next!=null&&cur.val==cur.next.val){
int val = cur.val;
// 跳过重复节点
while(cur.next!=null&&cur.next.val==val)
cur = cur.next;
// 若开头即是重复元素,则更新pHead
if(preNode==null)
pHead = cur.next;
else // 反之更新preNode
preNode.next = cur.next;
}else{
preNode = cur;
}
cur = cur.next;
}
return pHead;
}
}
该代码中如下部分:
// 若开头即是重复元素,则更新pHead
if(preNode==null)
pHead = cur.next;
else // 反之更新preNode
preNode.next = cur.next;
将preNode和pHead刚开始指向同一个节点,之后将不再移动pHead,通过preNode的移动,将新的链表穿起来~
第四题:
(4)、删除具有指定val值的节点
思路:这个也不难,首先我们判断该节点是不是需要删除的节点,如果是的话,借助题目1中删除该节点的方法来搞定。判断该节点是中间节点?还是最后一个节点?如果是最后一个节点,则需要从前到后遍历链表。注意只有一个节点的情况,即要删除的节点是头结点同时也是尾节点。
public class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head==null)
return null;
if(head.next==null&&head.val==val)
return null;
if(head.next==null&&head.val!=val)
return head;
ListNode cur = head;
while(cur!=null){
// 如果是准备删除的元素
if(cur.val==val){
if(cur.next!=null){
// 要删除的不是最后一个元素
cur.val = cur.next.val;
if(cur.next.next!=null)
cur.next = cur.next.next;
else
cur.next = null;
// 直接continue
continue;
}else{
// 要删除的是最后一个元素
ListNode node = head;
// 防止出现即是第一个也是最后一个几点的情况
if(node==cur)
return null;
while(node.next!=cur){
node = node.next;
}
node.next = null;
}
}
cur = cur.next;
}
return head;
}
}
第五题:
(5)、删除倒数第N个节点
思路:链表中遇到倒数N,K 啥的问题一般都是双指针来搞定。本题,设立两个指针,一个先走N步之后,两个指针同时走,这样当前面的指针走到最后时,后面的指针走到了要删除的倒数第N个节点,我们调整该节点的指向,删除该节点即可。
public class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head==null)
return null;
ListNode slow = head;
ListNode fast = head;
while(n>0&&fast!=null){
fast = fast.next;
n--;
}
if(fast==null)
return head.next;
while(fast.next!=null){
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return head;
}
}
如果对你有帮助,记得点赞哦~欢迎大家关注我的博客,可以进群366533258一起交流学习哦~
本群给大家提供一个学习交流的平台,内设菜鸟Java管理员一枚、精通算法的金牌讲师一枚、Android管理员一枚、蓝牙BlueTooth管理员一枚、Web前端管理一枚以及C#管理一枚。欢迎大家进来交流技术。
单链表删除(Delete)或者去除(Remove)节点面试题总结的更多相关文章
- 单链表 C++ 实现 - 含虚拟头节点
本文例程下载链接:ListDemo 链表 vs 数组 链表和数组的最大区别在于链表不支持随机访问,不能像数组那样对任意一个(索引)位置的元素进行访问,而需要从头节点开始,一个一个往后访问直到查找到目标 ...
- 以K个为一组反转单链表,最后不足K个节点的部分也反转
package StackMin.ReverseList_offer16; public class ReverseKgroup_extend_offer16 { /** * 分组反转单链表,最后不足 ...
- 20140719 找到单链表的倒数第K个节点 判断一个链表是否成为一个环形 反转
1.找到单链表的倒数第K个节点 2.判断一个单链表对否形成环形 3.单链表翻转
- C语言实现单链表(不带头结点)节点的插入
对单链表进行增删改查是最主要的操作.我在上一篇博客<C语言实现链表节点的删除>实现了删除单链表中的某个节点. 这里我们要来实如今某个位置插入节点.演示样例代码上传至https://gith ...
- Leetcode24--->Swap Nodes in Pairs(交换单链表中相邻的两个节点)
题目:给定一个单链表,交换两个相邻的节点,且返回交换之后的头节点 举例: Given 1->2->3->4, you should return the list as 2-> ...
- iOS常用算法之单链表查找倒数第n个节点(图解)
拿到题目, 首先要先了解链表数据结构, 如下图: 常规思路: 利用数组, 遍历整个单链表, 将每个节点装入数组中, 最终拿到数组根据索引(数组长度-1-n)就得到了倒数第n个元素, 这里要注意从数组中 ...
- 面试题-----求单链表的倒数第k个节点
#include <iostream> using namespace std; struct node{ int value; struct node *next; }; struct ...
- C++循环单链表删除连续相邻重复值
比如:1(头)->2->2->3->3->1->1(头) 去除以后的结果是1->2->3,注意头尾的1也要去掉一个. #include "st ...
- C++获取单链表的倒数第k个节点
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ c ...
随机推荐
- 常用restful路由
tax_categories GET /tax_categories(.:format) tax_categories#index POST /tax_categories(.:format) tax ...
- 2018 Multi-University Training Contest 1 - B Balanced Sequence (贪心)
题意:对N个由(,)组成的字符串,求拼接后得到的最大的balance序列的长度.balance序列:空串/ A+B(A,B都是b序列)/ (+A+),A为b序列.此三种情况. 分析:在读入N每个字符串 ...
- Mysql:实现分组查询拼接未分组同一字段字符group_concat()
Mysql:实现分组查询拼接未分组同一字段字符group_concat() MySQL中,如果想实现将分组之后的多个数据合并到一列,可以使用group_concat函数,如下图所示: 在oralce中 ...
- MySQL性能优化之max_connections参数
很多开发人员都会遇见”MySQL: ERROR 1040: Too many connections”的异常情况,造成这种情况的一种原因是访问量过高,MySQL服务器抗不住,这个时候就要考虑增加从服务 ...
- Linux下多线程下载工具MWget和Axel使用介绍
linux运维在操作linux过程中,用得最多的linux下载工具想必一定是wget,没有看到哪一台服务器没装过wget的,或许有人使用ftp下载,也有人使用多线程的axel以及ProZilla,毫无 ...
- Introspector内省和反射的区别.
Introspector 是一个专门处理bean的工具类.用来获取Bean体系里的 propertiesDescriptor,methodDescriptor. 要理解这个,就要理解下面几个议题. ...
- zabbix 邮件报警
一.设置sendmail 安装sendmail yum install -y sendmail systemctl start sendmail.service 配置 cd /usr/lib/zab ...
- java基础(2)--进制
进制 进制基础, 目的:理解计算机只能处理2进制的数据和指令 1)10进制计数规律 数字: 0 1 2 3 4 5 6 7 8 9 基数:10 权: 1000 100 10 1 权是基数的n次幂 2 ...
- Java中Collections.sort()排序详解
public static void main(String[] args) { List<String> list = new ArrayList<String>(); ...
- java socket - 半关闭
通常,使用关闭输出流来表示输出已经结束.但在进行网络通信时则不能这样做.因为我们关闭输出流时,该输出流对应的Socket也将随之关闭,这样程序将无法再从该socket中读取数据. 为了应付这种情况,s ...