(尊重劳动成果,转载请注明出处: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)节点面试题总结的更多相关文章

  1. 单链表 C++ 实现 - 含虚拟头节点

    本文例程下载链接:ListDemo 链表 vs 数组 链表和数组的最大区别在于链表不支持随机访问,不能像数组那样对任意一个(索引)位置的元素进行访问,而需要从头节点开始,一个一个往后访问直到查找到目标 ...

  2. 以K个为一组反转单链表,最后不足K个节点的部分也反转

    package StackMin.ReverseList_offer16; public class ReverseKgroup_extend_offer16 { /** * 分组反转单链表,最后不足 ...

  3. 20140719 找到单链表的倒数第K个节点 判断一个链表是否成为一个环形 反转

    1.找到单链表的倒数第K个节点 2.判断一个单链表对否形成环形 3.单链表翻转

  4. C语言实现单链表(不带头结点)节点的插入

    对单链表进行增删改查是最主要的操作.我在上一篇博客<C语言实现链表节点的删除>实现了删除单链表中的某个节点. 这里我们要来实如今某个位置插入节点.演示样例代码上传至https://gith ...

  5. Leetcode24--->Swap Nodes in Pairs(交换单链表中相邻的两个节点)

    题目:给定一个单链表,交换两个相邻的节点,且返回交换之后的头节点 举例: Given 1->2->3->4, you should return the list as 2-> ...

  6. iOS常用算法之单链表查找倒数第n个节点(图解)

    拿到题目, 首先要先了解链表数据结构, 如下图: 常规思路: 利用数组, 遍历整个单链表, 将每个节点装入数组中, 最终拿到数组根据索引(数组长度-1-n)就得到了倒数第n个元素, 这里要注意从数组中 ...

  7. 面试题-----求单链表的倒数第k个节点

    #include <iostream> using namespace std; struct node{ int value; struct node *next; }; struct ...

  8. C++循环单链表删除连续相邻重复值

    比如:1(头)->2->2->3->3->1->1(头) 去除以后的结果是1->2->3,注意头尾的1也要去掉一个. #include "st ...

  9. C++获取单链表的倒数第k个节点

    /* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ c ...

随机推荐

  1. python全栈开发从入门到放弃之网络基础

    一.操作系统基础 操作系统:(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才 ...

  2. 使用PHP模拟post提交数据

    使用PHP模拟post提交数据 分类: PHP LAMP 2013-04-13 12:03 3954人阅读 评论(0) 收藏 举报 CurlsocketPHP 这也是个老生常谈的话题了,上午花了点时间 ...

  3. 解释一下python中的身份运算符

    通过身份运算符‘is’和‘is not’,我们可以确定两个值是否相同 ')#False print(True is not False)#True

  4. 使用阿里的maven库

    快使用阿里云的maven仓库 自从开源中国的maven仓库挂了之后就一直在用国外的仓库,慢得想要砸电脑的心都有了.如果你和我一样受够了国外maven仓库的龟速下载?快试试阿里云提供的maven仓库,从 ...

  5. Javascript中call()和apply()的用法 ----1

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

  6. angularJs十个面试题

    一.ng-show/ng-hide 与 ng-if的区别? 我们都知道ng-show/ng-hide实际上是通过display来进行隐藏和显示的.而ng-if实际上控制dom节点的增删除来实现的.因此 ...

  7. django---ORM之Q查询

    filter 等方法中的关键字参数查询都是一起进行“AND” 的. 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q对象 调用Q from django.db.models import Q ...

  8. Windows 10 调节缩略图背景透明度

    A goal is a dream with a deadline. Much effort, much prosperity. 用Windows 10 的朋友都知道 win10 确实挺好用,但是做的 ...

  9. 关于C/C++中main函数参数的学习

    因为面对对象作业(2018.5.21)的要求,去学习了C/C++中main函数参数的意义,以及一些简单的使用(从命令行指令的接受),不给予赘述.(仅为个人拙见,还望看官指正) 首先,带有参数的main ...

  10. spark学习10(win下利用Intellij IDEA搭建spark开发环境)

    第一步:启动IntelliJ IDEA,选择Create New Project,然后选择Scala,点击下一步,输入项目名称wujiadong.spark继续下一步 第二步:导入spark-asse ...