剑指 Offer -- 删除链表中重复的节点(五十六)
原创
©著作权归作者所有:来自51CTO博客作者珍妮的选择的原创作品,请联系作者获取转载授权,否则将追究法律责任
删除链表中重复的节点(五十六)
题目描述:
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
代码(已在牛客上 AC)
在判断是否有重复值时, 用了一种看起来有点冗余的写法, 在 if (p->next && p->next->val == p->val)
对重复值进行判断之后, 然后又在 while (pn && pn->val == p->val)
做了同样的判断, 但是感觉这样写, 代码容易读一点. 最后 pn
指向某个与 p->val
不同的值, 或者直接为空, 都没有关系, 令 p = pn
, 然后 continue
进行新一轮的判断即可.
class Solution {
public:
ListNode* deleteDuplication(ListNode *root) {
if (!root || !root->next) return root;
auto p = root;
ListNode *dummy = new ListNode(0);
auto ptr = dummy;
while (p) {
if (p->next && p->next->val == p->val) {
auto pn = p->next;
while (pn && pn->val == p->val) pn = pn->next;
p = pn;
continue;
}
ptr->next = p;
ptr = ptr->next;
p = p->next;
}
// 注意这一步不能忘记, 最后要将结尾置为空. 比如
// {1, 2, 5, 5}, 最后 ptr 是指向 2 的, 如果
// 不设置结尾为空, 会把后面两个 5 给带上...
ptr->next = nullptr;
return dummy->next;
}
};
另一种写法, 也 AC, 但是呢, 写的年代有点久远了, 当初没写个注释, 现在不愿花时间再看了…
class Solution {
public:
ListNode* deleteDuplication(ListNode* root) {
if (!root || !root->next) return root;
ListNode *dummy = new ListNode(0);
ListNode *k = dummy;
ListNode *prev = root, *ptr = prev->next;
int value = root->val;
while (ptr) {
if (ptr->val == value) ptr = ptr->next;
else {
if (prev->next == ptr) {
k->next = prev;
k = k->next;
}
prev = ptr;
value = prev->val;
ptr = prev->next;
}
}
k->next = prev->next ? nullptr : prev;
return dummy->next;
}
};