题目描述
输入一个链表,输出该链表中倒数第k个结点。k从1开始计数。
算法分析
普通思路:
先确定链表的长度 n(需要一次遍历), 再根据 k 算出节点正数的位置,通过再次遍历确定返回的节点。此方法需要两次遍历链表,难以让面试官满意
剑指Offer思路:
设置两个指针,p1 和 p2,它们之间正好有 k 节点,之后 p1 和 p2 向后遍历,直到 p2 指向链表的尾结点,此时 p1 指向链表的倒数第 k 个节点,此方法只需要遍历链表一次。
代码鲁棒性提醒
有了好的思路,并不代表一定让面试官满意,要注意代码鲁棒性。针对此题目
- 输入的链表为空
- 输入的 k = 0
- 输入的 k 大于链表长度
这些特殊情况要予以考虑才能写出无BUG的代码
程序代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k)
{
if(pListHead==nullptr || k==0)
return nullptr;
ListNode* p1 = pListHead;
ListNode* p2 = pListHead;
unsigned int step = 0;
while(step < k-1)
{
p2 = p2->next;
step++;
if(p2 == nullptr)
return nullptr;
}
while(p2->next != nullptr)
{
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
};
相关题目
求链表的中间节点。如果链表节点总数为奇数,返回中间节点,如果链表节点总数为偶数,返回中间两个节点的任意一个。
思路
设置两个指针 p1 和 p2,每次 p1 走一步,p2 走两步,直到 p2 走到链表末尾,此时 p1 指向中间节点。
总结
对于链表的遍历问题,当用一个指针难以解决的时候,可以考虑用两个指针,这时候有两种考虑:
- 一个指针快,一个指针慢
- 一个指针先走 n 步,之后同时走