题目

题目来源:力扣(LeetCode)

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。
返回同样按升序排列的结果链表。

示例 1:
image.png

输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]

示例 2:
image.png

输入:head = [1,1,1,2,3]
输出:[2,3]

思路分析

双指针法

由题意可知,给定的链表已经是排好序的,因此重复的元素在链表中出现的位置是连续的,因此我们只需要对链表进行一次遍历,就可以删除重复的元素。

1、删除重复元素时链表的头节点可能会被删除,因此我们需要定义一个虚拟头节点,其后继指针指向链表的头节点:
2、定义一个 prev 指针指向虚拟头节点 dummyHead,用以将删除重复节点之后剩余的链表部分连接起来;定义一个 curr 指针,指向头节点

3、遍历链表,如果 curr 指针所指向节点的值与curr指针所指向节点的下一个节点的值相等,那么curr指针往后移动一位,prev指针则保持不动:
4、如果 curr 指针所指向节点的值与curr指针所指向节点的下一个节点的值不相等,则将prev指针所指向节点的后继指针指向 curr指针所指向节点的后一个节点,然后将 curr 指针往后移动一位:
5、接着将prev指针指向curr指针所指向的节点,然后curr指针则往后移动一位:
6、当curr.next指向null时,说明链表已经遍历完毕,链表中所有重复元素也已删除

  1. var deleteDuplicates = function(head) {
  2. if (head == null) return null;
  3. // 定义一个虚拟头节点,其后继指针指向头节点
  4. const dummyHead = new ListNode(-1, head);
  5. // 定义 prev 指针,初始时指向虚拟头节点
  6. let prev = dummyHead;
  7. // 定义 curr 指针,指向头节点
  8. let curr = prev.next;
  9. // 遍历链表
  10. while (curr != null && curr.next != null) {
  11. // 如果 curr 指针所指向的节点值与 curr 指针所指向节点的下一个节点的值不相等
  12. if (curr.val != curr.next.val) {
  13. // prev 指针往后移动一位
  14. prev = prev.next;
  15. // curr 指针往后移动一位
  16. curr = curr.next
  17. } else {
  18. // 如果 curr 指针所指向的节点值与 curr 指针所指向节点的下一个节点的值相等
  19. while (curr != null && curr.next != null && curr.val === curr.next.val) {
  20. // curr 指针往后移动,直到找到 curr.val != curr.next.val
  21. curr = curr.next;
  22. }
  23. prev.next = curr.next;
  24. curr = curr.next
  25. }
  26. }
  27. return dummyHead.next;
  28. };

单指针法

由于给定的链表是已经排好序的,因此重复的元素在链表中出现的位置是连续的,因此我们只需要对链表进行一次遍历,即可删除重复的元素。

由于链表的头节点也可能被删除,因此我们需要先定义一个虚拟头节点来指向链表的头节点。

然后我们定义一个 curr 指针,指向链表的虚拟头节点,随后开始遍历链表,如果当前 curr.next 与 curr.next.next 所对应节点的值相等,那么我们就将 curr.next 以及后面与之相等的节点值的所有节点全部删除。我们记录下这个元素的值 x,随后不断将 curr.next从链表中删除,直到 curr.next 为空节点或者其节点值不等于 x 为止。此时,我们已经将链表中所有节点值为 x 的节点全部删除。

如果当前 curr.next 与 curr.next.next 所对应节点的值不相等,那么说明链表中只有一个节点值为 curr.next 的节点,那么我们就可以将 curr 指针指向 curr.next,即将curr指针往后移动一位。

当遍历完这个链表,所有重复的节点也已删除,我们返回返回链表的虚拟头节点的下一个节点。

  1. var deleteDuplicates = function(head) {
  2. if (!head) return head;
  3. // 定义一个虚拟头节点
  4. const dummyHead = new ListNode(-1, head);
  5. // 定义一个 curr 指针,指向虚拟头节点
  6. let curr = dummyHead;
  7. // 遍历链表
  8. while (curr.next && curr.next.next) {
  9. // 当前 curr.next 与 curr.next.next 所对应节点的值相等
  10. // 将 curr.next 及所有后面与之相同元素值的链表节点全部删除
  11. if (curr.next.val === curr.next.next.val) {
  12. const x = curr.next.val;
  13. while(curr.next && curr.next.val === x) {
  14. curr.next = curr.next.next;
  15. }
  16. } else {
  17. // 当前 curr.next 与 curr.next.next 所对应节点的值不相等,将 curr 指针往后移动一位
  18. curr = curr.next
  19. }
  20. }
  21. // 链表遍历完成,返回链表虚拟头节点的下一个节点
  22. return dummyHead.next;
  23. };