问题描述:给你一个链表的头节点 head 和一个整数 val,请你删除链表中所有满足 Node.val == val 的节点,并返回新的头节点 。
通过使用了虚拟头节点(dummy head)来简化链表的操作,特别是删除操作。
思路梳理:
- 创建虚拟头节点: 首先,创建一个额外的节点 dummy_head,它的 val 可以是任意值,它的 next 指向原始链表的头节点 head。这个虚拟头节点的作用是作为链表的入口点,使得在删除操作中不需要特别处理空链表的情况。
- 遍历列表并删除值为 val 的节点: 使用一个指针 current 初始化为 dummy_head,然后开始遍历链表。在每次迭代中,current 指针先移动到 current.next,然后检查 current.next 的值是否等于 val。如果等于 val,则将 current.next 更新为 current.next.next,这样就跳过了值为 val 的节点。如果 current.next 的值不等于 val,则 current 指针向前移动一位,指向 current.next。
- 返回新的头节点: 当遍历结束后,dummy_head.next 指针已经指向了链表中第一个非虚拟头节点的实际节点。因此,return dummy_head.next 实际上是返回了去除虚拟头节点之后的链表。
Python代码讲解:
在链表的删除操作中,虚拟头节点允许我们在不考虑链表是否为空的情况下,直接从链表的第二个节点开始操作,从而简化了代码。
1. 创建虚拟头节点:
dummy_head = ListNode(next = head)
这行代码创建了一个新的 ListNode 对象 dummy_head,其 val 属性默认为0(未显式设置),next 属性指向链表的头节点 head。这样,dummy_head 成为新的头节点,而原始的 head 节点变成了第二个节点。
2. 遍历列表并删除值为 val 的节点:
current = dummy_head
while current.next:
if current.next.val == val:
current.next = current.next.next
else:
current = current.next
这段代码使用 current 指针遍历链表。在每次迭代中,它检查 current.next 节点的值是否等于 val。如果相等,说明需要删除这个节点,因此将 current.next 更新为 current.next.next,从而跳过值为 val 的节点。如果 current.next 的值不等于 val,则 current 指针向前移动一位。
3. 返回新的头节点:
return dummy_head.next
最后,返回 dummy_head.next 作为新的头节点。由于 dummy_head 是一个虚拟点,它的下一个节点才是实际链表的第一个节点。
使用虚拟头节点的好处是,它简化了删除操作,特别是当需要删除头节点时。于 dummy_head 永远不会是 None,所以不需要特殊处理头节点为 None 的情况。此外,它还确保了删除操作的一致性,因为删除任何节点(包括头节点)的方法都是相同的。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
# 创建虚拟头部节点以简化删除过程
dummy_head = ListNode(next = head)
# 遍历列表并删除值为val的节点
current = dummy_head
while current.next:
if current.next.val == val:
current.next = current.next.next
else:
current = current.next
return dummy_head.next
注释:
while current.next:是什么意思呢
在Python中,while current.next: 是一个循环结构,它意味着要 current.next 的值不为 None(即 current 指针指向的下一个节点存在),循环就会继续执行。
具体来说,这个循环的工作流程如下:
- 检查 current.next 是否为 None。
- 如果 current.next 是 None,循环结束,程序继续执行循环外的代码。
- 如果 current.next 不是 None,循环继续执行循环体中的代码。
在这个特定的代码片段中,循环体是:
if current.next.val == val:
current.next = current.next.next
else:
current = current.next
循环体的作用是:
- 如果 current.next 的值等于 val,则将 current.next 更新为 current.next.next,这样就跳过了值为 val 的节点。
- 如果 current.next 的值不等于 val,则将 current 指针向前移动一位,指向 current.next。
这样,循环会继续执行,直到current.next 变为 None,此时循环结束,程序返回 dummy_head.next 作为新的头节点。