力扣LeetCode #82 删除排序链表II(DeleteDuplicates)

给定一个排序链表,该题目要求删除所有重复的节点,仅保留没有重复出现的数字。通过比较链表中相邻节点的值来判断并移除重复节点。本文提供思路分析和JAVA实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

- 题目描述

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字。

来源:LeetCode

- 示例

  • 示例 1:
    输入: 1->2->3->3->4->4->5
    输出: 1->2->5
  • 示例 2:
    输入: 1->1->1->2->3
    输出: 2->3

- 思路分析

  • 本题和#83有点相像,但本题仅保存没有重复出现的元素。相比于#83,头节点和尾节点需要特殊考虑,以及新链表的头节点确定相对比较麻烦。
  • 因为链表是有序的,那么很容易判断一个元素是否重复。我们定义 t e m p temp temp h e a d head head,令 h e a d = t e m p . n e x t head = temp.next head=temp.next。然后比较 t e m p . v a l , h e a d . v a l , h e a d . n e x t . v a l temp.val, head.val, head.next.val temp.val,head.val,head.next.val。注意我们比较这三个数,仅仅是为了确定head能否加入新链表 t e m p temp temp是已经考虑过的元素,不用管。
    ①如果满足 t e m p . v a l < h e a d . v a l < h e a d . n e x t . v a l temp.val<head.val<head.next.val temp.val<head.val<head.next.val,说明 h e a d head head没有重复,可以加入新链表。
    ②如果不满足,说明 h e a d head head一定重复,可能和 t e m p temp temp重复,可能和 h e a d . n e x t head.next head.next重复,也可能三个节点值相等。如果 t e m p temp temp h e a d head head重复,我们就知道 h e a d head head不可能加入链表,就改变 t e m p temp temp指向 h e a d head head h e a d head head指向 h e a d . n e x t head.next head.next,然后同样判断 h e a d head head;如果是 h e a d head head h e a d . n e x t head.next head.next重复,说明这两个元素都不可能加入链表,因此需要判断的是 h e a d . n e x t . n e x t head.next.next head.next.next,因此令 h e a d head head指向 h e a d . n e x t . n e x t head.next.next head.next.next,而 t e m p temp temp仍然指向新 h e a d head head的前一位,即改变之前的 h e a d . n e x t head.next head.next
  • 原链表头节点的特殊处理:因为头节点没有 t e m p temp temp,因此我给原链表加上一个值为 h e a d . v a l − 1 head.val-1 head.val1的节点作为新头节点,然后令 t e m p temp temp指向新的头节点,这样可以判断 h e a d head head是否重复。
  • 原链表尾节点的特殊处理:当退出循环后,说明已经到了链表的结尾。此时有两种可能:
    h e a d = = n u l l head == null head==null t e m p temp temp指向最后一位, h e a d head head为空。那么前面找到的链表就是最终结果,因为我们不考虑 t e m p temp temp,仅考虑 h e a d head head
    h e a d . n e x t = = n u l l head.next == null head.next==null t e m p temp temp指向链表的倒数第二个元素, h e a d head head指向链表的最后一个元素。此时如果两个节点值相等,前面找到的链表就是最终结果;如果两个节点的值不相等,那么需要将 h e a d head head加入链表。
  • 新的头节点:新的头节点有可能不存在,此时所有的元素都重复。
    ①如何确定新链表的头节点?如果存在,即为第一个不重复的元素值。此时即体现出了将 n e w H e a d newHead newHead的初始值设为 h e a d . v a l u e − 1 head.value-1 head.value1的原因:保证这个值是唯一的。当找到一个不重复元素,如果此时 n e w H e a d newHead newHead的值是 h e a d . v a l u e − 1 head.value-1 head.value1,我们就知道这个元素应该作为新链表的头节点。
    ②处理尾节点时,要记住此时头节点可能为空。

- 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 temp = new ListNode(head.val-1);  //在最前面添加一个头
        temp.next = head;
        int value = head.val;  //当head改变,head.val也会变,因此先保存成常量
        ListNode newHead = new ListNode(value-1); 
        ListNode hold = newHead;
        //比较三个连续的数,temp, head, head.next
        //iff temp.val<head.val<head.next.val, head可以保留在链表中
        //if temp.val == head.val, 说明head不能留,将temp和head分别后移一位
        //if head.val == temp.val, 说明head和temp都不能留,将temp指向head.next,head指向temp.next
        while(temp!=null && head!=null && head.next!=null) {
            if(head.val > temp.val && head.val < head.next.val) {
                if(newHead.val == value-1) {
                    newHead = head;
                    hold = newHead;
                }
                else {
                    hold.next = head;
                    hold = hold.next;
                }
                temp = head;
                head = head.next;
            }
            else {
                if(temp.val == head.val) temp = head;
                else if(head.val == head.next.val) temp = head.next;
                head = temp.next;
            }
        }
        
        if(head == null) { //temp是最后一位,head是空
            if(newHead.val == value-1) return head;  //没有满足条件的
            else {
                hold.next = head;
                return newHead;
            }
        }
        
        //temp是倒数第二位,head是最后一位的情况
        if(temp.val != head.val) {  //值不相等,添加head
            if(newHead.val == value-1) return head;
            else hold.next = head;
        }
        else {  //值相等
            temp = head.next;
            if(newHead.val == value-1) return temp;
            else hold.next = temp;
        }
        return newHead;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值