【问题标题】:Return the kth element from the tail (or end) of a singly linked list从单链表的尾部(或尾部)返回第 k 个元素
【发布时间】:2013-02-17 04:53:23
【问题描述】:

【面试题】

编写一个函数,该函数将一次性返回整数单链表尾部(或尾部)的第 5 个元素,然后针对该函数提供一组测试用例。

类似于问题:How to find nth element from the end of a singly linked list?,但我有一个额外的要求,我们应该只遍历链表一次。

这是我的解决方案:

struct Lnode  
{
    int val;
    Lnode* next;
    Lnode(int val, Lnode* next=NULL) : val(val), next(next) {}
};


Lnode* kthFromTail(Lnode* start, int k)
{
   static int count =0;
   if(!start)
        return NULL;

   Lnode* end = kthFromTail(start->next, k);
   if(count==k) end = start;
   count++;
   return end;
}

我只遍历链表一次并使用隐式递归堆栈。另一种方法是有两个指针:快速和慢速,快速的指针比慢速指针快 k 指针。哪个似乎更好?我认为使用两个指针的解决方案会很复杂,例如:奇数长度列表、偶数长度列表、k > 列表长度等。这个采用递归的方法很干净,涵盖了所有这些情况。

【问题讨论】:

  • 我想到的两指针解决方案很简单,唯一的特殊情况是如果列表的长度是< k。这在某种程度上对应于您的if (count == k) 条件。
  • @dacwe。我还能如何计算从末端遍历的节点数?

标签: algorithm recursion linked-list


【解决方案1】:

2 指针解决方案不符合您的要求,因为它遍历列表两次。

您的内存使用更多 - 确切地说是 O(n)。您正在创建一个与列表中的项目数相等的递归堆栈,这远非理想。

从最后一项中查找第 k 个...

更好的(单遍历)解决方案 - Circular buffer:

使用 O(k) 额外内存。

有一个长度为 k 的数组。

对于每个元素,在数组的下一个位置插入(带环绕)。

最后,只返回数组中下一个位置的项目。

2 指针解决方案:

遍历列表两次,但仅使用 O(1) 额外内存。

以 p1 和 p2 开头。

增加 p1 k 次。

而 p1 不在末尾
递增 p1 和 p2

p2 指向最后一个元素的第 k 个。

【讨论】:

  • 很好 - 就像你的圆形阵列替代品。 (+1)
  • 非常喜欢您基于圆形阵列的解决方案。如果允许使用额外的内存,那就太好了。
  • @user1071840 请注意,递归解决方案比循环数组使用更多内存。每次递归调用(= 列表中的项目数)比存储对数组中项目的单个引用要使用更多的内存(因为您需要存储所有局部变量和函数中要继续的位置)。因此该数组整体使用较少的内存(假设 k 项目数时可以使用循环链表实现)。
【解决方案2】:
'n' is user provided value. eg, 5 from last.

int gap=0 , len=0;
myNode *tempNode;

while (currNode is not NULL)
{
 currNode = currNode->next;
 gap = gap+1; 
 if(gap>=n)
   tempNode = currNode;
}
return tempNode;

【讨论】:

    猜你喜欢
    • 2021-07-23
    • 2013-11-12
    • 1970-01-01
    • 2014-07-03
    • 1970-01-01
    • 2015-10-19
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    相关资源
    最近更新 更多