如何解决在链表操作中使用哨兵节点 反复
当我通过提供的解决方案遇到“哨兵/虚拟节点”的概念时,我正在解决Leetcode上Remove Linked List elements上的一个问题。在某些情况下,例如空列表或带有一个元素的列表等,使用这样的节点应该可以简化“链接列表”中的操作。
问题描述是-
从具有值的整数链接列表中删除所有元素 值。
示例:
输入:1-> 2-> 6-> 3-> 4-> 5-> 6,val = 6输出:1-> 2-> 3-> 4-> 5
给定的解决方案是-
class Solution {
public ListNode removeElements(ListNode head,int val) {
ListNode sentinel = new ListNode(0);
sentinel.next = head;
ListNode prev = sentinel,curr = head;
while (curr != null) {
if (curr.val == val) prev.next = curr.next;
else prev = curr;
curr = curr.next;
}
return sentinel.next;
}
}
让我们考虑一下此链接列表-
1 -> 1 -> 2 -> 3 -> NULL
,要删除的节点的值为1
。
因此,结果列表应为2 -> 3 -> NULL
,其中列表中的head
指向2
。
在这一行中- sentinel.next = head;
使sentinel
成为列表中的第一个节点,其中next
节点为“ head”,如下所示-
0 -> 1 -> 1 -> 2 -> 3 -> NULL
,
-
请注意,
head
仍指向1
(列表中第一个值为1的节点)。 -
在while循环开始之前,我们将
prev
设置为sentinel
,将curr
设置为head
。 -
在循环期间,
prev
和curr
沿列表移动,都指向列表中的其他节点。请注意,head
仍指向前1个。 -
循环后,
prev
指向列表中的最后一个节点(值为3),而curr
变为null
。 -
但是,
head
仍引用列表中的第一个节点(值为1),而sentinel.next
引用此节点。因此,当我们运行return sentinel.next
->时,将获得对列表中第一个节点(值为1)的引用,该节点的next
属性未指向任何其他节点。因此,这本身就是一个节点。
那么这如何正常工作?应该返回的ListNode
应该指向值为2
而不是1
的节点。
这是基于我对Java中引用如何工作的了解。因为,当我们开始时-
ListNode sentinel = new ListNode(0);
sentinel.next = head;
ListNode prev = sentinel,curr = head;
我们得到类似的内容- [sentinel] -> [head]
,其中prev
指向sentinel
,curr
指向head
。
但是问题是prev
和curr
都在列表中更改了引用,而sentinel
和head
却没有。因此,sentinel.next
仍指向旧的head
。
修改1
为了使我的问题更清楚,这里有一个screenshot of the result。我想知道的是-sentinel.next
如何引用值为2
的节点?最初,sentinel.next
设置为head
,并且此位置没有任何改变。因此,sentinel.next
应该引用列表的原始head
-值为1
的节点。
编辑2
我想我明白了。更改发生在这一行prev.next = curr.next;
由于prev
和sentinel
都引用相同的列表元素(在此阶段),因此sentinel.next
的设置正确。
解决方法
- 我猜这可能是错误的:
当我们运行return sentinel.next->时,我们首先获得对此的引用 列表中的节点
-
我猜
-
prev
对于前两个值不会移动。仅其链接被移动到下一个节点。 -
另一件事是哨兵是
final
,不会改变:
class Solution {
public ListNode removeElements(
final ListNode head,final int val
) {
final ListNode sentinel = new ListNode(0);
sentinel.next = head;
ListNode prev = sentinel;
ListNode curr = head;
while (curr != null) {
if (curr.val == val) {
prev.next = curr.next;
}
else {
prev = curr;
}
curr = curr.next;
}
return sentinel.next;
}
}
-
也许需要注意的是,我们也没有
removing
任何值(内存中有值),我们只是在更改链接列表的链接。 -
最后,我们只对链接列表的头(
sentinel.next
)感兴趣,我们对prev
的位置不感兴趣。
反复
class Solution {
public ListNode removeElements(ListNode head,int val) {
if (head == null)
return null;
head.next = removeElements(head.next,val);
return head.val == val ? head.next : head;
}
}
1和1之间的链接仍然存在,忘了画出来。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。