leetcode
leetcode 51 ~ 100
删除排序链表中的重复元素

删除排序链表中的重复元素

难度:

标签:

题目描述

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

 

示例 1:

输入:head = [1,1,2]
输出:[1,2]

示例 2:

输入:head = [1,1,2,3,3]
输出:[1,2,3]

 

提示:

  • 链表中节点数目在范围 [0, 300]
  • -100 <= Node.val <= 100
  • 题目数据保证链表已经按升序 排列

代码结果

运行时间: 44 ms, 内存: 15 MB


/*
 * 思路:
 * 1. 将链表的所有值提取到一个列表中。
 * 2. 使用Stream API对列表进行去重操作。
 * 3. 将去重后的值重新构建成链表。
 */
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}
 
public class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) return null;
 
        List<Integer> values = new ArrayList<>();
        ListNode current = head;
 
        // 提取链表中的所有值
        while (current != null) {
            values.add(current.val);
            current = current.next;
        }
 
        // 使用Stream进行去重
        List<Integer> uniqueValues = values.stream().distinct().collect(Collectors.toList());
 
        // 重建链表
        ListNode newHead = new ListNode(uniqueValues.get(0));
        ListNode newCurrent = newHead;
        for (int i = 1; i < uniqueValues.size(); i++) {
            newCurrent.next = new ListNode(uniqueValues.get(i));
            newCurrent = newCurrent.next;
        }
 
        return newHead;
    }
}

解释

方法:

这个题解采用了一次遍历链表的方法。遍历过程中,如果当前节点和下一个节点的值相同,就将当前节点的 next 指针指向下一个节点的 next,这样就删除了重复的节点。如果当前节点和下一个节点的值不同,就将当前节点后移。遍历直到当前节点为空,表示处理完了整个链表。最后返回链表的头节点 head。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在`deleteDuplicates`函数中,如果链表只有一个元素或全部元素都不相同,函数的行为是如何的?
如果链表只有一个元素,该元素自然没有下一个节点来比较,因此`cur.next`为`None`,循环体不会执行,直接返回原链表头节点,即单个元素。如果链表中的所有元素都不相同,每次比较`cur.val`和`cur.next.val`都不会相等,因此`cur`指针会一直后移,直到链表末尾,循环结束后返回的还是原链表头节点。在这两种情况下,链表都不会被修改。
🦆
为什么在遍历链表时,只检查`cur.next`的存在性,而不是同时检查`cur`和`cur.next`的存在性?
在循环条件中只检查`cur.next`的存在性是因为`cur`的存在性在每次循环的开始已经隐含地被检查了。由于循环是从头节点开始,且每次迭代结束时,如果`cur.next`不存在(即`cur`是尾节点或后面没有节点),循环会自然结束。如果同时检查`cur`和`cur.next`的存在性,实际上是多余的,因为当`cur`为`None`时,循环已经无法继续。
🦆
在删除重复元素后,是否需要进行额外的操作来确保链表的其他部分仍然保持排序状态?
不需要进行额外的操作来确保链表的排序状态。算法的逻辑保证了只有连续且相同的元素会被删除,不会对原有的排序顺序产生影响。因为链表本身是预先排序的,删除操作只是去除了重复的元素,未改变非重复元素间的相对顺序。
🦆
当链表中有连续多个重复元素时(例如`[1,1,1,2]`),这个方法是否能有效地删除所有重复的节点?
是的,这个方法能有效地删除所有重复的节点。当遇到连续的重复元素时,例如`[1,1,1,2]`中的三个`1`,`cur`指针所指的节点的`val`与`cur.next.val`相同,因此会持续更新`cur.next`为`cur.next.next`,直到`cur.next`指向的节点值不再与`cur.val`相同。这样,所有连续重复的节点都会被删除,只留下一个`1`。

相关问题

删除排序链表中的重复元素 II

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

 

示例 1:

输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]

示例 2:

输入:head = [1,1,1,2,3]
输出:[2,3]

 

提示:

  • 链表中节点数目在范围 [0, 300]
  • -100 <= Node.val <= 100
  • 题目数据保证链表已经按升序 排列