力扣 83: 删除排序链表中的重复元素(Java实现)

问题描述

给定一个已排序的链表的头节点 head,删除所有重复的元素,使每个元素只出现一次。返回已排序的链表。

示例 :

复制代码
输入:head = [1,1,2,3,3]
输出:[1,2,3]

问题分析

这是一个经典的链表操作问题。由于链表已经排序,所有重复的元素都会相邻出现。我们需要遍历链表,当遇到重复元素时,跳过重复的节点。

关键点:

  1. 链表已排序,重复元素必然相邻

  2. 只需要保留每个元素的第一个出现

  3. 需要修改指针来跳过重复节点

解决方案

方法一:直接遍历法

这是最直观的解法。我们使用一个指针遍历链表,比较当前节点和下一个节点的值:

java 复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        // 如果链表为空或只有一个节点,直接返回
        if (head == null || head.next == null) {
            return head;
        }
        ListNode cur = head;
        while (cur != null && cur.next != null) {
            if (cur.val == cur.next.val) {
                // 跳过重复节点
                cur.next = cur.next.next;
            } else {
                // 移动到下一个不重复的节点
                cur = cur.next;
            }
        }
        return head;
    }
}

代码解析

直接遍历法详细解析

  1. 边界条件处理

    java

    复制代码
    if (head == null || head.next == null) {
        return head;
    }

    空链表或只有一个节点的链表不需要去重。

  2. 遍历链表

    java

    复制代码
    ListNode cur = head;
    while (cur != null && cur.next != null) {
        // 处理逻辑
    }

    使用 cur 指针遍历链表,需要同时检查 curcur.next 是否为空。

  3. 处理重复元素

    java

    复制代码
    if (cur.val == cur.next.val) {
        // 跳过重复节点
        cur.next = cur.next.next;
    } else {
        // 移动到下一个不重复的节点
        cur = cur.next;
    }
    • 如果当前节点和下一个节点的值相同,修改 cur.next 指针,跳过下一个节点

    • 如果值不同,正常移动到下一个节点

复杂度分析

时间复杂度: O(n)

  • 只需要遍历链表一次,每个节点最多被访问一次

空间复杂度:

  • 直接遍历法:O(1),只使用了常数级别的额外空间

常见错误

错误示例

java 复制代码
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        ListNode cur = head;
        while (cur != null) {
            ListNode p = cur.next;
            if (p.val != cur.val) {  // 可能空指针异常
                cur = p;
            }
            cur.next = p.next;  // 逻辑混乱
        }
        return head;
    }
}

错误分析:

  1. 空指针异常 :当 cur.nextnull 时,pnull,访问 p.val 会导致空指针异常

  2. 逻辑错误 :在 if 语句内部移动 cur,然后又在外部修改 cur.next,逻辑不清晰

  3. 可能跳过不重复节点 :当 p.val != cur.val 时,代码将 cur 移动到 p,然后立即修改 cur.next = p.next,这会跳过 p 节点

扩展思考

如果链表未排序怎么办?

如果链表未排序,我们需要使用额外的数据结构(如HashSet)来记录已经出现的元素。时间复杂度仍然是O(n),但空间复杂度变为O(n)。

如何删除所有重复元素(LeetCode 82)?

LeetCode 82要求删除所有重复出现的元素,只保留没有重复出现的元素。这需要更复杂的指针操作,因为需要完全删除重复元素,而不仅仅是去重。

总结

删除排序链表中的重复元素是一个基础的链表操作问题,关键在于理解指针的操作。直接遍历法是最常用的解法,具有O(1)的空间复杂度。递归解法虽然简洁,但有O(n)的空间复杂度。在实际面试中,建议使用直接遍历法,并注意处理边界条件。

关键技巧:

  1. 使用双指针或单指针遍历链表

  2. 比较相邻节点的值

  3. 通过修改指针来跳过重复节点

  4. 注意处理空指针异常

掌握了这个问题,可以帮助你更好地理解链表的基本操作,为更复杂的链表问题打下基础。

相关推荐
长安er2 小时前
LeetCode 62/64/5/1143多维动态规划核心题型总结
算法·leetcode·mybatis·动态规划
LYFlied2 小时前
【每日算法】LeetCode 208. 实现 Trie (前缀树)
数据结构·算法·leetcode·面试·职场和发展
Mr Tang2 小时前
Docker日志查看和应用日志查看命令大全
java·开发语言
invicinble2 小时前
java处理数据合集
java·开发语言
Json_2 小时前
springboot框架对接物联网,配置TCP协议依赖,与设备通信,让TCP变的如此简单
java·后端·tcp/ip
C+++Python2 小时前
Java 锁机制
java·开发语言
czlczl200209252 小时前
Spring Security 6 :配置生产级 SecurityFilterChain
java·spring
Java小白,一起学习2 小时前
AndroidStudio安装教程
java·android-studio
学编程就要猛2 小时前
算法:3.快乐数
java·算法