【问题标题】:Does a partial traversal of a linked-list count as "one pass" of the list?链接列表的部分遍历是否算作列表的“一次通过”?
【发布时间】:2025-12-27 17:45:11
【问题描述】:

我一直在通过 LeetCode 上的算法挑战,刚刚完成了“从列表末尾删除第 N 个节点”。

许多热门答案声称找到了“一次性”解决方案,我在下面提供了一个 Java 示例。

请有人解释一下为什么“while(n-->0) h2=h2.next;”不计为链表的额外通过,因此,将其设为“两次通过”解决方案?

public ListNode RemoveNthFromEnd(ListNode head, int n)  {
    ListNode h1=head, h2=head;

    while(n-->0) h2=h2.next;

    if(h2==null)return head.next;  // The head need to be removed, do it.

    h2=h2.next;
    
    while(h2!=null){
        h1=h1.next;
        h2=h2.next;
    }
    h1.next=h1.next.next;   // the one after the h1 need to be removed
    return head;
}

我在 cmets 中查看了此解决方案和其他解决方案,但找不到答案。同样,一般的 Google 搜索也没有给出解释。

提前致谢。

【问题讨论】:

  • 链接会很好。
  • 例如参见this 中的讨论。这是否是“一次通过”似乎是有争议的。
  • 我设法在您的第一个答案被删除前不久抓住了它,但它准确地解释了我在寻找什么 - 列表分两部分遍历的事实:第一个循环中的 1 到 n 和第二个列表中的其余部分。谢谢!
  • 可能是那些称其为“一次性”解决方案的人实际上意味着它是一个 O(n) 解决方案——这是真的。

标签: java algorithm loops linked-list


【解决方案1】:

不,这不是一次性的。 One-pass 是针对顺序 I/O 机制(通常是磁带)定义的,意味着每条数据最多按顺序读取一次。将链表类比为此处的磁带,该算法不是一次性的,因为一般情况下,某些节点的next 字段将被h2=h2.next(在任一循环中)读取一次,并在第二个循环中再次由h1=h1.next 读取.

【讨论】:

  • 我认为 do 算作一次通过的算法通常可以遵循 N+O(k) 下一个指针从 N- 末尾删除第 k 个节点长度列表。
  • @MattTimmermans 不,没有针对此的就地一次性算法,因为我们必须读取需要更改的节点才能知道我们需要更改它。
  • @DavidEisenstat:我认为这个标准还不够。通行证不必是部分的,也可以称为通行证。
  • @DavidEisenstat 最简单的方法是在 position%k == 0 时对节点指针进行采样,并记住最后 2 个样本。当你到达列表的末尾时,你可以计算最早记住的样本和目标节点之间的距离。这将是
【解决方案2】:

算法不是single pass,但不是因为第一次循环。

第一个循环对n 元素执行部分传递。

第二个循环对l-n 元素执行两个同时部分传递(h2 上的部分传递与第一个循环中的部分传递)。总共有2l-n 查找next 字段。

可以借助长度为 n 的 FIFO 队列来实现单通道解决方案,但这是“隐藏”部分通道。

【讨论】:

    最近更新 更多