题目:
题目解答:
运行结果:
思路:
一、读题
我记得有一题叫删除排序链表重复元素 Ⅰ:重复只留一个。
本题不一样!只要重复,全部干掉,一个不留。
(重点:链表是有序的)
二、思路
先试用head指针遍历,2→2→3。原始头节点是 2,但是 2 重复了,头节点本身要被删除。
如果直接操作 head,那最后返回的链表头就不是原来的 head 了。
考虑到上面所出现的问题所以使用虚拟头结点dummy。
这样不管原来链表的头节点要不要删掉,我们永远有一个固定的起点,最后只需要返回 dummy.next 就行。可以去解决链表头节点被删除的场景。
三、思考指针应该放在哪里
我们需要一个指针 cur。(1、cur 不能指向正在检查的节点。cur 要放在待检查片段的前驱节点。)
含义:cur 后面的节点,是我们要检查是否重复的区域。
cur 的作用:修改 cur.next,用来跳过重复节点。
初始状态:dummy → 1 → 2 →3→3→4→4→5(cur = dummy)cur 站在 dummy 的位置。
四、思考循环什么时候停
我们要判断 cur.next 和 cur.next.next 的值是否相等。
那必须保证 cur.next 和 cur.next.next 都不是空,否则访问 val 会报错。(循环条件:cur.next != NULL && cur.next.next != NULL)
(只要后面至少还有两个节点,才有判断重复的必要)
五、进入循环就两种情况。
情况 A:cur.next->val == cur.next.next->val(说明找到了重复值)
这个值不止两个,有可能连续很多个,比如1→1→1→2。不能只删两个,要把所有等于这个值的节点全部删掉。
先把这个重复的值存下来 repeatVal = cur.next->val 写内层循环:只要 cur.next 不为空,并且 cur.next 的值等于 repeatVal,就执行 cur.next = cur.next->next。 相当于把 cur 直接连到下下个节点,跳过当前这个重复节点。 重复执行,直到 cur.next 不再是 repeatVal,所有重复节点全部跳过。此时 cur不要移动,因为新的 cur.next 还需要继续判断是否重复。
举例子:2→2→2→3,cur 在 dummy,删完所有 2 之后,cur 还是 dummy,cur.next 指向 3,继续循环判断。
情况 B:cur.next->val != cur.next.next->val 说明 cur.next 这个节点没有重复,它要保留。
那 cur 往后移动一步:cur = cur.next。继续检查后面
六、结束,返回结果
return dummy.next。dummy.next 指向 1,链表是 1→2→5。和样例输出一致。