(尊重劳动成果,转载请注明出处: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. python16_day18【Django_Form表单、分页】

    一.表单 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 1.Form类 创建Form类时,主 ...

  2. Excel数据常用操作,vlookup,text,trim,数据格式导致出错

    数据有缺漏,需要在数据前面补零 =TEXT(F70,"000000") 前面是要操作的数据,后面是补几位 匹配数据(将一个表格中的数据进行匹配) =VLOOKUP(C2,aaa,4 ...

  3. python之元组操作

    1.元组创建 tup1 = ('physics', 'chemistry', 1997, 2000) tup2 = (1, 2, 3, 4, 5 ) tup3 = "a", &qu ...

  4. WPF MVVM模式下ComboBox级联效果 选择第一项

    MVVM模式下做的省市区的级联效果.通过改变ComboBox执行命令改变市,区. 解决主要问题就是默认选中第一项 1.首先要定义一个属性,继承自INotifyPropertyChanged接口.我这里 ...

  5. ES6 完全使用手册

    前言 这里的 "ES6" 泛指 ES5 之后的新语法 这里的 "完全" 是指本文会不断更新 这里的 "使用" 是指本文会展示很多 ES6 的 ...

  6. 将CString写入到本地文件中

    void SocketU::WritePacket2File(CString packet_str)//packet_str为待写入的字符串{ CTime time = CTime::GetCurre ...

  7. Facebook力推导航库:React Navigation使用详解

    本文来自Songlcy投稿:文章地址:http://blog.csdn.net/u013718120/article/details/72357698 一.开源库介绍 今年1月份,新开源的react- ...

  8. libc.so.6(GLIBC_2.14)(64bit) is needed by MySQL

    记一次粗心大意!解决办法在最下面! rpm安装MySQL时提升如下: warning: MySQL-client-5.6.41-1.el7.x86_64.rpm: Header V3 DSA/SHA1 ...

  9. FZU 1759 Super A^B mod C 指数循环节

    Problem 1759 Super A^B mod C Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description G ...

  10. Pandas与SQL比较

    由于许多潜在的Pandas用户对SQL有一定的了解,因此本文章旨在提供一些如何使用Pandas执行各种SQL操作的示例. import pandas as pd url = 'tips.csv' ti ...