打卡-算法训练营-Day3 | 203.移除链表元素;707.设计链表

61 阅读2分钟

链表删除操作

leetcode链接:leetcode.cn/problems/re…

画图不容易出错,删除链表元素:

image.png

这道题可以有两种解法:使用虚拟节点和不使用虚拟节点(今天只用了虚拟节点的方法,不使用的方法也可以了解下)

不使用虚拟节点

从上面的图看出,如果要删除元素的话,需要知道上一个节点的指针。

但头节点没有上一个节点,所以头节点需要特殊处理。

使用while遍历,使得链表中的头节点一定不等于val。

while (head && head.val === val) {
  head = head.next;
}

然后从头节点开始,遍历元素进行删除操作。

为什么需要一个临时指针等于head指针?

如果用head指针遍历元素,等遍历结束的时候,head指针已经指向链表的末尾了,无法返回新的头节点。使用临时指针遍历元素,最后直接返回head指针。

let cur = head;
while (cur && cur.next) {
   if (cur.next.val === val) {
       cur.next = cur.next.next;
   } else {
       cur = cur.next;
   }
}

使用虚拟节点

为什么需要虚拟头节点?

一般的节点在删除的时候,直接把前一个节点的next指向后一个节点即可。但是头节点没有前一个节点,可以在头节点前加一个虚拟头节点,就不需要特殊处理头节点了。

let dummy = new ListNode(0, head);

为什么需要一个临时指针等于dummy指针?

理由同上,不过要注意和不使用虚拟头节点时的区别。一个等于head指针,一个等于dummy指针。因为不使用虚拟头节点的方法,已经特殊处理过头节点了,但虚拟头节点还没有处理过。

使用虚拟头节点的方法,head指针一直没有变化过,一直都是原来链表。返回的时候不能返回head,而应该是dummy.next。

var removeElements = function(head, val) {
    // 使用虚拟头节点
    let dummy = new ListNode(0, head);
    // 要理解为什么cur要等于dummy而不是head
    let cur = dummy;

    // 要获取cur.next的val值,所以cur.next不能为空
    while (cur.next) {
        if (cur.next.val === val) {
            cur.next = cur.next.next;
        } else {
            cur = cur.next;
        }
    }
    return dummy.next;
};

设计链表

leetcode链接:leetcode.cn/problems/de…

考察链表综合操作的题目

明天补博客