(尊重劳动成果,转载请注明出处: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. beego——参数配置

    beego目前支持INI.XML.JSON.YAML格式的配置文件解析,但是默认采用了INI格式解析,用户可以通过简单的配置就可以获得很大的灵活性. 一.默认配置解析 beego 默认会解析当前应用下 ...

  2. s5_day3作业

    # 一.元素分类 # 有如下值集合[11, 22, 33, 44, 55, 66, 77, 88, 99, 90...],将所有大于 # # 的值保存至字典的第一个key中,将小于 # # 的值保存至 ...

  3. CNN学习笔记:全连接层

    CNN学习笔记:全连接层 全连接层 全连接层在整个网络卷积神经网络中起到“分类器”的作用.如果说卷积层.池化层和激活函数等操作是将原始数据映射到隐层特征空间的话,全连接层则起到将学到的特征表示映射到样 ...

  4. LeetCode 1. Two Sum 找到两数字求和索引集合

    https://leetcode.com/problems/two-sum/description/ 第一种方法  遍历查找 // // main.m // HFCDemo // // Created ...

  5. addEventListener和attachEvent介绍, 原生js和jquery的兼容性写法

    也许很多同仁一听到事件监听,第一想到的就是原生js的 addEventListener()事件,的确如此,当然如果只是适用于现代浏览器(IE9.10.11 | ff, chorme, safari, ...

  6. Linux系统启动管理 系统安全

    Linux GRUB加密方法 加密grub防止黑客通过单用户系统破解root密码 ,进入系统窃取数据.给grub加密,不让别人通过grub进入单用户.  生成密码 [root@localhost ~] ...

  7. C# Winform DataGrid 绑定List<> Or ObservableCollection<> 类型无法自动刷新问题

    当DataGrid通过绑定List<> Or ObservableCollection<> 类型数据,通过INofityPropertyChanged接口通知数据改变进行刷新无 ...

  8. [转]HBase hbck——检察HBase集群的一致性

    Hbase提供了hbck命令来检查各种不一致问题.hbck的名字仿效了HDFS的fsck命令,后者是一个用于检查HDFS中不一致问题的工具.下面这段非常易懂的介绍出自于hbck的源程序. 检查数据在M ...

  9. FTP vsftp 安装、管理

    FTP简介 FTP是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为文传协议,用户Internet上的控制文件的双向传输. FTP的主要作用,就是让用户链接上一个远 ...

  10. SQuirrel-GUI工具安装手册-基于phoenix驱动

    背景描述: SQuirrel sql client 官方地址:http://www.squirrelsql.org/index.php?page=screenshots 一个图形界面的管理工具 安装手 ...