题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留。
样例
输入:1->2->3->3->4->4->5
输出:1->2->5
样例2
输入:1->1->1->2->3
输出:2->3
算法
(线性扫描)
- 之前做的删除节点的题是有重复元素只保留1个下来,这道题的要求是一个都不保留。(有点狠兄弟)
- 那么就要求在
cur
指针还没扫到重复元素区间的第一个元素的时候,就知道它们是重复元素了。 - 那么针对于2,解决方法是新建一个指针
go
,go = cur->next
。就像cur
相当于是上帝视角,是大佬,go
是小兵向前冲。一般第一步cur->next->val
是一定等于go->val
的,接下来是继续判断,如果有重复元素,小兵go
会继续向前冲,最后碰到不同元素,跳出while
循环。 - 逻辑是这样:如果cur的后面是有一段相同元素,cur是不会涉足这段元素的,go会遍历这一段的每一个元素。最后,cur是相同元素区间的前一个节点,go是相同元素区间的后一个节点。
- 接下来的
if
判断,if(cur->next->next == go)
成立意味着cur和go之间没有重复元素,那么cur向前走一步。如果else
成立,说明有重复元素,那么cur->next
指向go
,直接略过相同元素这一段,相当于删除了这一段。 - 我的问题有2个,第1个:为什么是
cur->next = go
,而不是直接cur = go
。 - 第2个,
dummy->next
是怎么工作的,哪里改了dummy
的next指向。
时间复杂度
$O(n)$
C++ 代码
class Solution {
public:
ListNode* deleteDuplication(ListNode* head) {
ListNode *dummy = new ListNode(-1);
dummy->next = head;
auto cur = dummy;
while(cur->next)
{
auto go = cur->next;
while(go && cur->next->val == go->val) go = go->next;
if(cur->next->next == go) cur = cur->next;
else cur->next = go;
}
return dummy->next;
}
};
同问第7点
画图就明白了
懂了,p修改之前的指向
tql