力扣 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. 注意处理空指针异常

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

相关推荐
风生u1 分钟前
activiti7 详解
java
岁岁种桃花儿10 分钟前
SpringCloud从入门到上天:Nacos做微服务注册中心(二)
java·spring cloud·微服务
Word码13 分钟前
[C++语法] 继承 (用法详解)
java·jvm·c++
@––––––14 分钟前
力扣hot100—系列2-多维动态规划
算法·leetcode·动态规划
TT哇19 分钟前
【实习 】银行经理端两个核心功能的开发与修复(银行经理绑定逻辑修复和线下领取扫码功能开发)
java·vue.js
逝水如流年轻往返染尘22 分钟前
Java中的数组
java
java1234_小锋39 分钟前
Java高频面试题:BIO、NIO、AIO有什么区别?
java·面试·nio
用户8307196840821 小时前
Java IO三大模型(BIO/NIO/AIO)超详细总结
java
sheji34161 小时前
【开题答辩全过程】以 基于SSM的花店销售管理系统为例,包含答辩的问题和答案
java
Mr_sun.1 小时前
Day09——入退管理-入住-2
android·java·开发语言