83. 删除排序链表中的重复元素

347 阅读2分钟

题目描述

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 。

分析

输入:链表的头节点 head 输出:变换之后的链表头节点

解题思路

这道题目,我们用两种方法解,第一种方式是我上来就想到的双指针方法,另一种是官网提供的一次遍历

双指针

对于双指针的解法,我们需要定义 fast, slow 两个指针,fast会先走。
对于本题,我会让 fast 一直向前走,直到它的 val 不等于 slow 的值,才会做一些操作。

我们看张图:

image.png

第一次操作发生在 fastdummyHead 走到 1 的时候,第二次是从到 3 的时候,那为了方便,我拿第二次举例。

此时 slow 指向 1,fast 指向 3,很显然我们需要做的是把 slow.next 指向 3,这样中间重复的元素都会被跳过,链表中只剩下 1 ➡️ 3 两个。

我们看下代码:

代码

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var deleteDuplicates = function (head) {
  if (!head) return null;

  const dummyHead = new ListNode(null, head);
  let slow = dummyHead,
    fast = dummyHead;

  while (fast) {
      // 当 fast,slow 指向不同的时候,我们进行操作,把 slow 的 next 指向 fast
      // 这样链表里重复的元素只保留了一个,剩下的都被删除
    if (slow.val !== fast.val) {
      slow.next = fast;
      slow = fast;
    }

    // 移动 fast
    fast = fast.next;
  }
  // 因为最后 fast 是 null 的时候,没有把前面的元素链接 🔗 过来,所以这里做下处理
  slow.next = fast;

  return dummyHead.next;
};

一次遍历

这种方法是力扣官方题解,比我那个简单。

解释下,因为重复的元素都是连续的,所以只要遍历一次,然后只要发现了连续的元素,那么就在原地去把后边重复的 next 节点全部删掉,在向后遍历就可以了,我们看下代码:

代码

var deleteDuplicates = function (head) {
  if (!head) return null;
  let cur = head

// 我们删的是 next
  while (cur.next) {
    if (cur.val === cur.next.val) {
      cur.next = cur.next.next;
    } else {
      cur = cur.next;
    }
  }

  return head;
};