力扣83删除排序链表中的重复元素:代码实现+思路分析+方法总结(快慢指针法&递归)

简介: 力扣83删除排序链表中的重复元素:代码实现+思路分析+方法总结(快慢指针法&递归)

第一部分:题目描述

🏠 链接:83. 删除排序链表中的重复元素 - 力扣(LeetCode)

⭐ 难度:简单

第二部分:代码实现

2.1 快慢指针法

步骤:

  1. 当节点数小于2时,则不会发生重复节点的情况,无需删除,直接返回。
  2. 设置快慢指针,慢指针指向头节点head,快指针指向 head 的下一个节点。
  3. 使用fast指针遍历链表,每次对 fast.val 与 slow.val 进行比较。
  • 快慢指针的val值相等,说明当前链表中还存与当前slow指向节点的值相等的节点。不需要理会当前fast指向的节点,直接向后移动一位。当 fast和last的val值不相等的时候,将slow的下一个节点设置为fast即可达到跳过重复节点的效果。
  • 快慢指针的val值不相等,说明不再存在与当前slow指向的值相等的其他节点。设置 slow 的下一个节点为当前 fast 指向的节点来达到跳过重复节点的效果,slow后移,fast后移。
  1. fast 已遍历完链表,为null,slow 也应该指向 null,以跳过 slow 与 fast 之间的节点(肯定是重复节点)。
  2. 返回头节点。
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        // 当节点数小于2时,则不会发生重复节点的情况,无需删除,直接返回
        if (head == null || head.next == null) {
            return head;
        }
        // 慢指针
        ListNode slow = head;
        // 快指针,初始指向 head 的下一个节点
        ListNode fast = head.next;
        // fast 遍历链表,fast == null 说明遍历完成
        while (fast != null) {
            if (slow.val == fast.val) {
                // 情况一:快慢指针的val值相等,说明当前链表中还存与当前slow指向节点的值相等的节点
                // 不需要理会当前fast指向的节点,直接向后移动一位
                // 当 fast和last的val值不相等的时候,将slow的下一个节点设置为fast即可达到跳过重复节点的效果
                fast = fast.next;
            } else {
                // 情况二:快慢指针的val值不相等,说明不再存在与当前slow指向的值相等的其他节点
                // 2.1 设置 slow 的下一个节点为当前 fast 指向的节点
                slow.next = fast;
                // 2.2 slow 向后移动
                slow = slow.next;
                // 2.3 fast 向后移动
                fast = fast.next;
            }
        }
        // fast 已遍历完链表,为null,slow 也应该指向空
        // 例如链表:1 -> 1 -> 3 -> 3 -> null
        // fast为null时,slow 为第一个3,则需要跳过第二个3,那么 slow 指向 null 或者 fast 即可 
        slow.next = null;
        // 返回头节点
        return head;
    }
}

2.2 递归

递归函数负责返回:从当前节点(我)开始,完成去重的链表

  1. 若我与 next 重复,返回 next
  2. 若我与 next 不重复,返回我,但 next 应当更新
deleteDuplicates(ListNode p=1) {
    deleteDuplicates(ListNode p=1) {
        1.next=deleteDuplicates(ListNode p=2) {
            2.next=deleteDuplicates(ListNode p=3) {
                deleteDuplicates(ListNode p=3) {
          // 只剩一个节点,返回
                    return 3
                }                
            }
            return 2
        }
        return 1
    }
}

代码:

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        // 如果无节点或到了最后一个节点,则返回 null 或 最后一个节点即可
        if (head == null || head.next == null) {
            return head;
        }
        if (head.val == head.next.val) {
            // 如果当前节点的val与下一个节点的val相等
            // 则返回下一个节点,就是不保留当前节点,只保留下一个节点
            return deleteDuplicates(head.next);
        } else {
            // 如果当前节点的val与下一个节点的val不相等
            // 则更新当前节点的next
            head.next = deleteDuplicates(head.next);
            // 返回当前节点
            return head;
        }
    }
}


相关文章
【力扣】-- 移除链表元素
【力扣】-- 移除链表元素
158 1
|
2月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
180 1
|
6月前
|
存储
203. 移除链表元素,707.设计链表,206. 反转链表
链表是数据结构中的重要概念,包含单链表、双链表和循环链表。单链表每个节点存储数据与下一节点指针;双链表增加上一节点指针;循环链表首尾相连。 **例题解析:** 1. **203. 移除链表元素**:通过遍历链表删除指定值节点,注意处理头节点特殊情况。 2. **707. 设计链表**:实现链表的增删查操作,需理解指针操作逻辑,避免直接修改目标节点。 3. **206. 反转链表**:采用双指针或递归方法改变节点指向,完成链表反转。 以上题目涵盖链表核心操作,掌握后可灵活应对相关问题。
链表指针的传参,传值和传地址
本文讨论了链表操作中指针传参的问题,特别是指针的传值与传地址的区别,并提供了修正代码,以确保链表插入操作能正确地修改指针指向的地址。
119 1
链表指针的传参,传值和传地址
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
328 0
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
169 0
【LeetCode 06】203.移除链表元素
【LeetCode 06】203.移除链表元素
122 0
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
256 6
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
367 2