返回

攻破难题:除链表中重复的节点,斩获完美offer

前端

攻破链表难关:巧用虚拟头节点,逐个击破重复节点

在程序员求职之路上,剑指 Offer 是一个绕不开的关卡,而链表操作又是其中一个难点。重复节点问题更是让不少求职者饮恨沙场。今天,我们就来详解如何巧用虚拟头节点,逐个击破重复节点,助你轻松过关斩将。

虚拟头节点:链表操作的利器

在解决重复节点问题之前,我们先来了解一下虚拟头节点的概念。虚拟头节点是一个特殊节点,它并不属于链表本身,而是作为链表的起始点,为链表的操作提供了一个统一的入口。它的引入,让链表的操作更加方便,也更具通用性。

举个例子,对于一个链表 1 -> 2 -> 3 -> 4 -> 5,我们可以引入一个虚拟头节点 0,使其指向链表的第一个节点 1。这样一来,链表就变成了 0 -> 1 -> 2 -> 3 -> 4 -> 5。虚拟头节点 0 不参与任何具体操作,它只是为了方便我们对链表进行操作,比如添加、删除或修改节点。

逐个击破:解决重复节点问题的关键

明确了虚拟头节点的作用后,我们就可以开始解决重复节点的问题了。所谓的重复节点,是指链表中存在两个或多个值相同的节点。我们的目标是将所有重复节点删除,只保留一个。

要做到这一点,我们可以采用逐个比较的策略。首先,我们设置两个指针,一个指向当前节点,另一个指向它的前驱节点。然后,我们逐个比较当前节点和它的前驱节点的值,如果相等,则说明当前节点是重复节点,我们需要将其删除。否则,我们将当前节点的前驱指针指向当前节点,并继续比较下一个节点。

代码示例:实战演练

为了让上述步骤更加清晰,我们用代码来演示一下。假设我们有一个名为 Node 的链表节点类,其中包含一个名为 val 的属性,用于存储节点的值,以及一个名为 next 的属性,用于指向下一个节点。

class Node:
    def __init__(self, val):
        self.val = val
        self.next = None

def remove_duplicates(head):
    if head is None or head.next is None:
        return head

    dummy = Node(0)
    dummy.next = head

    pre = dummy
    cur = head

    while cur:
        if cur.val == pre.val:
            pre.next = cur.next
        else:
            pre = cur

        cur = cur.next

    return dummy.next

在代码中,我们首先判断链表是否为空或只有一个节点,如果是则直接返回链表。然后,我们创建一个虚拟头节点 dummy,并将其指向链表的第一个节点。接着,我们使用两个指针 precur,分别指向当前节点和它的前驱节点。

我们在循环中逐个比较 cur 节点和 pre 节点的值,如果相等,则说明 cur 节点是重复节点,我们需要将其删除。具体做法是将 pre 节点的 next 指针指向 cur 节点的 next 指针,这样就跳过了 cur 节点。否则,我们更新 pre 节点,使其指向 cur 节点。

最后,我们返回虚拟头节点 dummynext 指针,即链表的第一个节点。

结语:披荆斩棘,自信前行

通过上面的讲解和代码示例,相信你已经掌握了如何删除链表中重复节点的方法。虚拟头节点的使用,逐个比较的策略,以及代码的实现,这些都为你扫清了障碍,让你能够自信地面对 Offer 战场上的挑战。

在未来的编程征途中,你会遇到更多难题,但只要你保持一颗积极的心态,不断磨砺自己的算法技能,就能在一次次攻关中不断提升自己,成为一名真正的编程高手。祝你在 Offer 战场 上披荆斩棘,斩获胜利!

常见问题解答

1. 为什么需要使用虚拟头节点?

虚拟头节点可以简化链表操作,它提供了一个统一的入口,让链表的添加、删除和修改操作更加方便。

2. 如何判断一个节点是否重复?

我们通过逐个比较当前节点和它的前驱节点的值来判断是否重复。如果相等,则说明当前节点是重复节点。

3. 为什么需要逐个比较节点的值?

逐个比较可以保证我们不会遗漏任何重复节点。如果我们采用其他策略,比如使用哈希表,则可能会因为哈希冲突而导致重复节点没有被删除。

4. 代码中为什么使用 pre.next 指针来跳过重复节点?

pre.next 指针指向当前节点的前驱节点,而当前节点是重复节点,因此我们只需要更新 pre.next 指针,使其指向当前节点的 next 指针,即可跳过重复节点。

5. 如何处理链表中相邻的重复节点?

代码中使用的逐个比较策略可以正确处理相邻的重复节点。当我们遇到相邻的重复节点时,pre 指针会连续跳过这些重复节点,直到遇到不重复的节点。