首页 > 其他分享 >删除链表结点类问题

删除链表结点类问题

时间:2022-08-21 02:22:33浏览次数:57  
标签:结点 ListNode cur 删除 next 链表 prev

删除链表结点

NO1. 删除链表倒数第 k个结点

给定一个链表,删除链表的倒数第 n 个节点并返回链表的头指针。要求:空间复杂度 \(O(1)\),时间复杂度 \(O(n)\)

如果倒数第 k 个结点刚好是头结点,那头结点需要特殊处理。为了各个结点能等同操作,设置一个虚拟头结点。

寻找倒数第 k 个结点常使用“快慢双指针”来实现。

算法流程:

  • step 1 :在原头结点前面添加一个虚拟头结点;
  • step 2 :使用快慢指针找到倒数第 k+1 个结点(有了前驱结点,第 k 个结点才能删掉);
  • step 3 :删除倒数第 k 个结点,返回头结点;

代码实现:

public class Solution {
    static class ListNode {
        int val;
        ListNode next = null;
    }
    
    public ListNode removeNthFromEnd (ListNode head, int k) {
        // 1. 添加一个虚拟头结点
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        // 2. 使用快慢指针找到倒数第 k+1 个结点
        ListNode prev = getNode(dummy, n);
        // 3. 删除 倒数 第 k 个结点
        prev.next = prev.next.next;
        return dummy.next;
    }
    // 找到倒数第 k+1 个结点
    public ListNode getNode(ListNode newHead, int k) {
        ListNode slow = newHead, fast = newHead;
        for(int i = 0; i <= k; i++)		fast = fast.next;
        while(fast != null) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

复杂度分析:

  • 时间复杂度:\(O(n)\),其中 \(n\) 为链表长度;
  • 空间复杂度:\(O(1)\),无额外辅助空间使用;

NO2. 删除有序链表中重复元素Ⅰ

删除给出链表中的重复元素(链表中元素从小到大有序),使链表中的所有元素都只出现一次。例如:给出的链表为1→1→2→3→3,返回1→2→3。

进阶:空间复杂度 O(1),时间复杂度O(n)

对于重复元素,仅保留第一个,后面重复地直接跳过。

算法流程:

  • step 1 :特殊情况判断(空链表或仅有一个结点的链表);
  • step 2 :使用两个工作指针,一个指向重复元素的第一个结点(若存在),另一个往后遍历去重;

每轮循环结束时 prev 始终都是 cur 的前驱。

代码实现:

public class Solution {
    
    static class ListNode {
        int val;
        ListNode next = null;
    }
    
    public ListNode deleteDuplicates (ListNode head) {
        if(head == null || head.next == null)    return head;
        ListNode cur = head.next, prev = head;
        
        while(cur != null) {
            // 元素重复,要删掉 cur
            if(prev.val == cur.val) {
                prev.next = cur.next;
            } else {
                // 没重复的 prev 了,prev 指向 cur,对下一个值进行去重
                prev = cur;
            }
            cur = cur.next;
        }
    }
}

复杂度分析:

  • 时间复杂度:\(O(n)\),其中 \(n\) 为链表长度;
  • 空间复杂度:\(O(1)\),无额外辅助空间使用;

NO3. 删除有序链表中重复元素Ⅱ

跟上一题的区别就在于,上一题的所有元素都至少会保留一个,而本题中只要有重复,重复结点一个也不保留。

例如:1→2→3→3→4→4→5,返回1→2→5.

本题跟上题不同,如果头结点重复了,那头结点就得删除,为了方便操作,添加一个虚拟头结点。

算法流程:

  • step 1 :特殊情况判断(空链表或仅有一个结点的链表);

  • step 2 :添加一个虚拟头结点,为了方便删除第一个结点;

  • step 3 :还是利用两个工作指针,每次就比较相邻两个元素是否相等,

    • 相等的话就跳过所有重复结点(一个不留);
    • 不相等,prev 指针后移,去判断 prev 下一个元素是否有重复;
  • step 4 :返回虚拟头结点的 next;

代码实现:

    public ListNode deleteDuplicates (ListNode head) {
        // 口 -> 1 -> 1 -> 2 -> 3 -> 3
        if(head == null || head.next == null)    return head;
        
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        
        ListNode prev = dummy, cur = dummy.next;
        
        while(cur != null && cur.next != null) {
            if(cur.val == cur.next.val) {
                // 相邻元素相等,跳过
                while(cur.next != null && cur.val == cur.next.val) {
                    cur = cur.next;
                }
                // 上面while结束,cur指向有重复的最后一个元素,这一步实现跳过所有重复结点
                prev.next = cur.next;
            } else {
                // 相邻元素不相等,prev指针后移,指向cur
                prev = cur;
            }
            cur = cur.next;
        }
        return dummy.next;
    }

复杂度分析:

  • 时间复杂度:\(O(n)\),其中 \(n\) 为链表长度;
  • 空间复杂度:\(O(1)\),无额外辅助空间使用;

小结

删除链表类问题,通常使用双指针来操作,prev指针来得到待删结点的前驱,cur指针用于得到待删结点的后继,通过两工作指针就能解决链表删除问题。

此外,如果头结点可能被删除,那就要构造一个虚拟头结点,方便删除头结点。

标签:结点,ListNode,cur,删除,next,链表,prev
From: https://www.cnblogs.com/afei688/p/16609245.html

相关文章

  • springMvc38-restful的crud实现删除方式
    上图·是目录结构,本节是有问同学的,当好好总结pom.xml   <projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instan......
  • EditPlus 删除空行的正则表达式(Windows)
    http://www.slyar.com/blog/editplus-regexp-blankline.html遇到一个比较大的文本文件需要去除空行,首先想到的自然是正则表达式。偷懒去网上找了几个删除空行的正则表达......
  • 链表应用题
    1.递归删除指定值(无头结点)voidDel(ListNode*L,intval){ListNode*p;//指向被删除节点if(L==NULL)return;//递归边界if(L->val==val){//处理首指针......
  • 旋转、移动、删除和重新编号 PDF 页面
    https://helpx.adobe.com/cn/acrobat/using/manipulating-deleting-renumbering-pdf-pages.html......
  • redis集群新增结点slot迁移原理
    redis集群新增结点slot迁移原理写在前面:最近在复习redis知识点,遇到一个问题很疑惑,就是集群新增结点时,是将slot重新分配,然后移动?这样集群节点之间不就需要互相传送数据吗,......
  • go语言 单向链表
    //示例45packagemainimport"fmt"funcmain(){varintlinkLinkfori:=0;i<10;i++{intlink.InsertTail(i)}......
  • Log4NET 日志分割删除与压缩解决思路(附源码)
    最近公司发现,日志产生的太多了,于是让我写个方法来解决,一开始是让我删除,后来想了想让我先压缩再删除文件夹,下面提供两个版本的源代码及简单使用。注:这两个代码也是博主CV的......
  • 删除选中功能代码实现
    删除选中功能代码实现publicclassDelUserServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)t......
  • 删除选中功能、删除选中功能代码实现
    删除选中功能图解  删除选中功能代码实现jsp页面c:forEachitems="${users}"var="user"varStatus="s"><tr><td><inputtype="checkbox"></td>......
  • 记录进程隐藏的挖矿病毒bioset其删除全过程
    服务器感染bioset挖矿病毒后,一般手段找不出来,因为该程序通过手段隐藏了进程,搜了搜,linux一般自带unhide命令,没有的话执行下yuminstallunhide,遇到确认项时按y输出确......