题目:
输入一个链表,输出该链表中倒数第k个结点。为符合计数习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例子
如:一个链表有6个节点,从头节点开始,它们的值一次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
链接:
剑指Offer(第2版):P134
思路标签:
- 数据结构:链表
- 算法:双指针
- 代码的鲁棒性
解答:
1. C++
- 因为是单向链表,所以无法从后向前遍历;
- 一种直观的思路是先遍历链表得到链表的长度,然后第二次遍历就能找到第k个节点,但是需要进行两次遍历,不是好的方法;
- 这里使用两个指针实现一次遍历,第一个指针先走k-1步,第二个指针一直不动;然后两个指针同时移动,知道第一个指针遍历完成。因为两个指针间隔为k-1,所以第二个指针指向的节点即为倒数第k个节点。
- 需要注意代码的鲁棒性:
- 链表为空;
- k == 0,以为k为无符号整数,k-1=0xFFFFFFFF,导致错误;
- 链表数不够k的情况,也就是第一个指针移动过程中变为nullptr。
/*
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* pAhead = pListHead;
ListNode* pBehind = nullptr;
for(unsigned int i=0; i<k-1; i++){
if(pAhead->next != nullptr)
pAhead = pAhead->next;
else
return nullptr;
}
pBehind = pListHead;
while(pAhead->next != nullptr){
pAhead = pAhead->next;
pBehind = pBehind->next;
}
return pBehind;
}
};
相关题目
求链表的中间节点,如果链表中的节点总数为奇数,则返回中间节点;如果节点总数是偶数,则返回中间两个节点的任意一个。
- 为了解决这个问题,我们也可以定义两个指针,同时从链表的头节点出发,一个指针一次走一步,另一个指针一次走两步。
- 当走得快的指针走到链表的末尾时,走得慢的指针正好在链表的中间。