删除排序链表中的重复元素
608 字
3 分钟
删除排序链表中的重复元素
题目链接:83. 删除排序链表中的重复元素 - 力扣(LeetCode)
- 难度:简单
- 标签:链表
题目描述
Note
原题说明:
给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
示例 1
graph LR
A((1)) --> B((1)) --> C((2))
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#f9f,stroke:#333,stroke-width:2px
输出:[1, 2]
示例 2
graph LR
A((1)) --> B((1)) --> C((2)) --> D((3)) --> E((3))
输出:[1, 2, 3]
方案:迭代指针(跳过重复项)
核心思路: 由于链表已经排好序,重复的元素一定是相邻的。
- 让当前指针
cur指向head。 - 比较
cur和cur->next的值。 - 如果相等,说明找到了重复元素,让
cur->next指向cur->next->next(即跳过重复节点)。 - 如果不相等,则移动
cur指针到下一个节点。
源码实现
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */class Solution {public: ListNode* deleteDuplicates(ListNode* head) { if (!head) return nullptr;
ListNode* cur = head; // 当当前节点和下一个节点都存在时 while (cur && cur->next) { if (cur->val == cur->next->val) { // 原则:发现重复,直接跨过重复节点 cur->next = cur->next->next; } else { // 原则:没有重复,正常移动指针 cur = cur->next; } } return head; }};复杂度分析
- 时间复杂度:。其中 是链表的长度。我们只需遍历一次链表。
- 空间复杂度:。我们只使用了常数级的额外指针变量。
避坑指南:= 与 ==
Caution
血泪教训:
在编写 cur->next = cur->next->next 时,千万不要写成 cur->next == cur->next->next。
==是比较运算符,它不会改变指针的指向。- 如果写错,会导致
while循环无法打破(或逻辑停滞),从而引发死循环。
总结
- 链表精髓:理解
next指针的重新定向是链表操作的灵魂。 - 内存安全:在实际工程中,跳过的节点(被删除的重复元素)通常需要手动释放内存(
delete),但在 LeetCode 的简单题中通常不需要严苛考虑这一点。 - 有序特性:正是因为有序,我们才只需要比较相邻节点,而不需要使用额外的哈希表来记录。
Tip
链表题目看起来花哨,但只要脑子里有一张“连线图”,代码实现往往比数组还要简洁!
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
最后更新于 2025-10-20,距今已过 191 天
部分内容可能已过时
相关文章 智能推荐
1
合并两个有序链表
算法 力扣第21题:合并两个有序链表。从“先合并再排序”的暴力思维,到归并与递归的优雅实现。
2
删除有序数组中的重复项
算法 力扣第26题:原地删除有序数组中的重复项。从基础的标记替换,到快慢指针(Two Pointers)的高效演进。
3
移除元素
算法 力扣第27题:原地移除数组中所有等于 val 的元素。深入理解快慢指针在乱序数组中的灵活应用。
4
最后一个单词的长度
算法 力扣第58题:最后一个单词的长度。从反向遍历的直观思想到双指针的精准定位,掌握字符串处理的边界细节。
5
合并两个有序数组
算法 力扣第88题:合并两个有序数组。从正向合并的繁琐到逆向双指针的极简之美,实现 $O(m+n)$ 的高效原地合并。
随机文章 随机推荐