【问题标题】:How would you get the nth node from the tail in a singly linked list (in one traverse)?如何从单向链表的尾部获取第 n 个节点(一次遍历)?
【发布时间】:2013-09-28 19:58:36
【问题描述】:

所以我从考试中得到了这个问题。

如何从单链表的尾部获取第 n 个节点?

每个节点都有一个值和一个下一个(指向下一个值的指针)。我们得到了这个:

getNodeFromTail(Node head, int x) {

}

所以我这样做的方法是通过遍历一次来找到列表的长度。然后再去获取 (length - x) 节点。所以总共有 2 次遍历。

getNodeFromTail(Node head, int x) {
    int length = 0;
    Node headdupe = head;
    while (headdupe.next != NULL) {
         headdupe = headdupe.next;
         length++;
    }
    int a = length--;
    for (int y = 0; y < a; y++) {
         head = head.next;
    }
    return head;
}

这是对的,但还有一个额外的问题是询问我们是否可以做同样的事情,但只遍历一次。考试的时候想不出来,后来想了一个办法,但又不太确定。

我可以创建一个长度为 x 的 ArrayList。然后每次我运行while循环时,我都会在数组的顶部添加一个元素,向下级联并启动数组的最后一个元素。然后当头部命中null时,返回数组[x-1]处的节点。

这是对的吗?有没有更好的解决方案?

【问题讨论】:

  • 我不太确定您在最后一段中所说的内容,但如果我不必担心会浪费大小的东西,我会说制作一个节点指针向量并作为您进行第一次迭代,将节点指针附加到遍历的每个节点的向量。然后当你到达最后,vector[list.length-x]。这几乎违背了链表的重点,但我认为这就是问题的重点。
  • 这个问题很可能希望您使用递归解决方案。
  • @iCode4Food ...或者意识到您可以将最后一个 x 头保存在内存中。
  • @iCode4Food 这将需要堆栈上的O(n) 额外内存,因此与将整个链表复制到数组并从后面获取xth 元素一样有效。

标签: algorithm linked-list singly-linked-list


【解决方案1】:
  1. 创建 2 个指向第一个节点的指针
  2. 将指针前移一个x
  3. 并排推进两个指针,直到列表中的另一个指针到达末尾。
  4. 您的指针向后指向最后一个元素 xth。

【讨论】:

  • 所以如果 x == 1 你基本上遍历列表两次。
  • @iCode4Food 不过,您只需支付一次循环开销,因此这种方式仍然更快。
  • 这取决于您对“遍历列表两次”的定义。自然,您将按照 2*N-x Next 指针来查找 N 大小的列表,在该列表中查找到最后一个元素的 x,但同时,此方法一次执行,而不是两次。
【解决方案2】:

我会做以下事情:

保留一个大小为x 的循环缓冲区,并在遍历列表时将节点添加到其中。当您到达列表的末尾时,尾部的第 x 个等于循环缓冲区中的下一个条目。

在伪代码中:

Node getNodeFromTail(Node head, int x) {
  // Circular buffer with current index of of iteration.
  int[] buffer = new int[x];
  int i = 0;

  do {
    // Place the current head in its position in the buffer and increment
    // the head and the index, continuing if necessary.
    buffer[i++ % x] = head;
    head = head.next;
  } while (head.next != NULL);

  // If we haven't reached x nodes, return NULL, otherwise the next item in the
  // circular buffer holds the item from x heads ago.
  return (i < x) ? NULL : buffer[++i % x];
}

此解决方案需要在内存中增加一个x,并且是用运行时间换取内存的经典示例。

注意:如果输入列表小于x,则未定义。

【讨论】:

  • 他的数组长度为x,你的数组长度为x,你的前两句话我没看懂。
  • @GuyGreer OPs 方法在每一步中移动所有数组元素,导致O(n + x^2) 运行时间,而这种方法使用循环数组并在O(n) 中运行
  • 我同意你的方法运行得更快,但你说的是`将额外内存的数量限制为 x. Unless I misunderstood the OP's idea he wouldn't be using more memory than x`。
  • @GuyGreer OP 创建一个初始容量列表x 并继续将元素推送到该数量之外,因此它将使用比x 更多的内存。
  • @Benoit 他“开始”最后一个元素,所以列表的大小不会超过x+1
【解决方案3】:

维护2个指针, 从开始处将第一个指针提前到第 N 个节点 现在指向第二个指向头部的指针 现在继续前进两个指针,直到第一次到达终点 第二个指针现在指向倒数第 N 个

如果列表中的元素少于 N 个,请格外小心

【讨论】:

  • 所以如果 N == 1 你基本上遍历列表两次。
【解决方案4】:

你可以在不遍历两次或递归的情况下做到这一点。 请参阅以下内容:

int getNodeFromTail(Node head, int position)
{
    if (head == NULL)
      return 0;

      // 2 pointers needed
      Node first = head;
      Node sec = head;

      for(int i = 0; i < position; i++)
        sec = sec.next;

      while (sec.next != NULL)
      {
        sec = sec.next;
        first = first.next;
      }

      return first;
}

【讨论】:

    【解决方案5】:

    您不需要 2 个效率低下的循环,只需使用 2 个指针和一个计数器:

    Node getNodeFromTail(Node head, int x)
    {
        Node p = head;
        Node q = head;
    
        int diff = 0;
    
        while (p.next != NULL)
        {
            p = p.next;
    
            if (diff >= x)
                q = q.next;
            else
                diff++;
        }
        return q;
    }
    

    【讨论】:

      【解决方案6】:

      这是最简单的解决方案

      static int getNodeNoStack(ListNode head, int k) {
          ListNode result = head;
          int count = 0;
          while(head.next != null) {
              if(count < k) {
                  count++;
              } else {
                  result = result.next;
              }
              head = head.next;
          }
          return result.val;
      }
      

      您只需将指针“结果”保持在距离 head 的 k 处,遍历整个列表直到结束。一旦 head 位于末尾,则结果指针将位于 tail 的第 k 个位置

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-08-08
        • 1970-01-01
        • 2018-01-27
        • 2019-07-05
        • 1970-01-01
        • 1970-01-01
        • 2023-01-28
        相关资源
        最近更新 更多