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

716 阅读3分钟

正题

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

存在一个按升序排列的链表,给你这个链表的头节点 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]

与前文 删除链表中重复的元素 相比,完全删除了出现多次的元素,包含第一次出现也会被删除,这样以来难度稍微提升了一点,因为我们需要多删除一次首次出现的情况。可以参考上文,做一次删除,然后记录下删除的元素,再一次遍历,再将同 val 值首次出现的情况删除掉即可完成。

但是这样没有创新,并且需要二次遍历链表。如何做到只遍历一次链表,删除所有重复的元素(包含首次出现的那一次)呢?

由题可以知道,链表是升序的,那么链表中的相同的元素一定是相邻的

能用图的绝不打字,下面试图用一张动图来表达我的思路:

1.gif

总体思路:

1.定义一个 head 作为 firstPre 节点,为什么要定义 firstPre 呢,因为链表是单向的,如果发现了重复,想要删掉当前的就需要重新遍历,如果在当前节点前面再定一个节点,就可以方便删除当前节点。

2.比较 first (当前节点) 和 next (下一个节点),由于链表的递增性,相同的节点必然是相邻的,也就是 first 和 next 可能会出现重复,所以比较 first 和 next

3.如果不相同,那么 firstPre 向右移动,这样会产生新的 first 和 next (first 为 firstPre.next , next 为 first.next)

4.一直比较 first 和 next ,如果相同,那么删除 next (将 first 指向 next.next),接着标记first,继续比较.这里可能会有两个疑问:(1)为什么要标记first?因为相同,那么 讲道理first节点也是要被删除的,当前仅删除了next节点,之所以没有删除它,那是因为要考虑可能会出现3个相同的连在一起,如果删除了first,第二个重复的就无法找到了。(2)为什么firstPre不右移了?同理,需要考虑到是否会存在3个相同的节点相邻,右移会导致疏漏。

5.如果依然相同,继续4操作

6,出现不同时,执行3操作,并且删除标记节点。

show my code:

/**
 * 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) {
    let temp = new ListNode(0)
    temp.next = head
    let firstPre = temp
    let isDeleteFirst = false
    do {
        console.log(firstPre)
        const first = firstPre ? firstPre.next : p
        if (first === null) {
            break
        }
        const next = first.next
        if (next && first.val === next.val) {
            // 删除 next, 标记 first
            isDeleteFirst = true
            first.next = next.next
            continue
        } else {
            if (isDeleteFirst) {
                firstPre.next = first.next
                isDeleteFirst = false
            } else {
              firstPre ? firstPre = firstPre.next : firstPre = head 
            }
        }
    } while (firstPre)
    return temp.next
};