删除排序链表中的重复元素:三种解法详解
问题描述
给定一个已排序的链表的头节点 head,要求删除所有重复元素,使得每个元素只出现一次。返回处理后的已排序链表。下面是leetcode题目如果感兴趣可以尝试一下。

方法一:递归解法
思路
递归法通过维护一个 ArrayList 来记录已遍历过的节点值。具体步骤如下:
-  将当前节点的值加入列表。 
-  递归处理下一个节点: -  如果下一个节点的值已存在于列表中,则跳过该节点(修改前驱节点的指针)。 
-  否则,继续递归处理。 
 
-  
class Solution {public ListNode deleteDuplicates(ListNode head) {if (head == null) return head;ArrayList<Integer> numbers = new ArrayList<>();numbers.add(head.val);deletenode(head, head.next, numbers);return head;}private void deletenode(ListNode pre, ListNode node, ArrayList<Integer> numbers) {if (node == null) return;if (numbers.contains(node.val)) {pre.next = node.next; // 删除当前节点deletenode(pre, node.next, numbers); // 继续处理下一个节点} else {numbers.add(node.val);deletenode(node, node.next, numbers); // 更新前驱节点}}
}复杂度分析
-  时间复杂度:O(n²),因为 ArrayList.contains()的时间复杂度为 O(n)。
-  空间复杂度:O(n),递归调用栈和列表的空间。 
缺点
-  递归深度可能达到链表长度,导致栈溢出。 
-  重复值检查效率低。 
方法二:迭代解法
思路
通过迭代遍历链表,使用 ArrayList 记录已存在的值。遇到重复值时,直接修改前驱节点的指针。
class Solution {public ListNode deleteDuplicates(ListNode head) {if (head == null) return head;ArrayList<Integer> numbers = new ArrayList<>();numbers.add(head.val);ListNode pre = head;ListNode node = head.next;while (node != null) {if (numbers.contains(node.val)) {pre.next = node.next; // 跳过重复节点} else {numbers.add(node.val);pre = node; // 更新前驱节点}node = node.next; // 移动指针}return head;}
}复杂度分析
-  时间复杂度:O(n²), ArrayList.contains()的线性检查导致性能瓶颈。
-  空间复杂度:O(n),存储已遍历值的列表。 
缺点
-  空间复杂度较高,不适用于大规模数据。 
方法三:直接遍历(最优解)
思路
利用链表已排序的特性,只需比较相邻节点的值:
优点
-  若当前节点与下一节点的值相同,则跳过下一节点。 
-  否则,移动指针继续遍历。 class Solution {public ListNode deleteDuplicates(ListNode head) {if (head == null) return head;ListNode cur = head;while (cur.next != null) {if (cur.val == cur.next.val) {cur.next = cur.next.next; // 删除重复节点} else {cur = cur.next; // 移动指针}}return head;} }复杂度分析
-  时间复杂度:O(n),只需一次遍历。 
-  空间复杂度:O(1),无需额外空间。 
-  高效且节省内存,完美利用链表有序的特性。 
方法对比
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 | 
|---|---|---|---|
| 递归解法 | O(n²) | O(n) | 小规模数据,不推荐实际使用 | 
| 迭代+ArrayList | O(n²) | O(n) | 未排序链表,但性能较差 | 
| 直接遍历 | O(n) | O(1) | 已排序链表,最优选择 | 
总结
对于已排序链表,方法三是最优解,其时间复杂度和空间复杂度均为最优。递归法和迭代法虽然逻辑简单,但在处理大规模数据时性能不足。建议根据链表是否有序选择合适的算法。
