删除链表结点类问题

删除链表结点

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

复杂度分析:

  • 时间复杂度:(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指针用于得到待删结点的后继,通过两工作指针就能解决链表删除问题。

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

Original: https://www.cnblogs.com/afei688/p/16609245.html
Author: 阿飞的客栈
Title: 删除链表结点类问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/617102/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Spring Cloud Gateway

    https://docs.spring.io/spring-cloud-gateway/docs/ https://cloud.spring.io/spring-cloud-gat…

    Java 2023年5月30日
    094
  • 【碎】bat 文件闪退

    解决办法:使用命令行窗口运行 bat 文件 posted @2022-09-25 15:41 HypoPine 阅读(43 ) 评论() 编辑 Original: https://…

    Java 2023年6月15日
    074
  • Mybatis xml文件中关于处理in操作的List取值

    关于foreach标签的问题 <select id="foreachDemo" resulttype="com.po.demo" pa…

    Java 2023年6月9日
    087
  • SpringBoot 定时任务不能同时运行的问题

    使用Spring Task可以非常方便的进行定时任务,但是默认只能有一个定时任务在执行。如何改变这种状况呢? 在定时任务方法上添加@Async注解即可。 java;gutter:t…

    Java 2023年5月30日
    099
  • 消息队列rabbitmq

    为什么用消息队列 举例 &#x6BD4;&#x5982;&#x5728;&#x4E00;&#x4E2A;&#x4F01;&#…

    Java 2023年5月30日
    085
  • Java添加条形码到PDF表格

    条码的应用已深入生活和工作的方方面面。在处理条码时,常需要和各种文档格式相结合。当需要在文档中插入、编辑或者删除条码时,可借助于一些专业的类库工具来实现。本文,以操作PDF文件为例…

    Java 2023年5月29日
    092
  • java常见面试题及答案

    1.什么是Java虚拟机?为什么Java被称作是”平台无关的编程语言”? Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程。Java 源文件被编…

    Java 2023年5月29日
    056
  • mybatis-plus 动态数据源 clickHouse集群

    背景: 当前项目使用的 mybatis-plus 多数据源框架,使用方式可参考:https://mp.baomidou.com/guide/dynamic-datasource.h…

    Java 2023年6月16日
    0102
  • 数据库架构演变概要

    一. 背景 为了适应业务增长,数据库数据量快速增长,性能日趋下降,稳定性不佳的实际情况,急需架构逐步演变适应未来的业务发展。 二. 现状 【稳定性】数据库为单点,没有高可用和稳定性…

    Java 2023年6月8日
    067
  • JavaWeb 11_文件上传

    一、操作步骤 1、要有一个form标签,method=post 请求2、form标签的encType属性值必须为multipart/form-data值3、在form标签中使用in…

    Java 2023年6月7日
    055
  • IDEA插件和个性化配置推荐

    插件推荐 我自己现在使用的一些插件和一些自己感觉比较舒服配置分析给大家 idea如何安装插件: 如果打开设置没有看到,直接搜索plugins 然后在这里搜索即可 CodeGlanc…

    Java 2023年6月6日
    0101
  • IDEA插件:快速删除Java代码中的注释

    有时,我们需要删除Java源代码中的注释。目前有不少方法,比如: 在上面的代码中,我们首先创建JavaParser,再解析源码,然后移除单行注释和块注释,最后再用LexicalPr…

    Java 2023年6月16日
    077
  • 我对java序列化的理解

    我对java序列化的理解 ​ 通过ObjectOutputStream输出流保存实体类所 产生的文件,每一个流都一个序列化ID,如果我们不设置UID的话,一旦我们修改代码,这个文件…

    Java 2023年6月7日
    091
  • Java maven反应堆构建学习实践

    实践环境 Apache Maven 3.0.5 (Red Hat 3.0.5-17) 应用示例 maven示例项目组织结构如下 maven-study &#x2502; p…

    Java 2023年5月29日
    080
  • Java——字节码技术

    字节码 1.1 什么是字节码? Java之所以可以”一次编译,到处运行”,一是因为JVM针对各种操作系统、平台都进行了定制,二是因为无论在什么平台,都可以编…

    Java 2023年5月29日
    0107
  • 两万字!多线程50问!

    前言 大家好,我是 捡田螺的小男孩。金九银十快要来了,整理了50道多线程并发面试题,大家可以点赞、收藏起来,慢慢品!~ github地址,麻烦给个star鼓励一下,感谢感谢 公众号…

    Java 2023年6月5日
    096
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球