输入一个单链表,输出该链表中的倒数第k个结点。链表的尾结点是倒数第1个结点。
分析:
- 最简单的思路是遍历链表,得到长度n,则倒数第k个结点就是从头结点开始的第(n-k+1)个结点。从头结点开始走n-k+1步即可找到。
- 上述解法需要遍历链表2次。其实遍历1次也可以。这种题目的套路是设置两个指针。一个指针较快,一个指针较慢。快慢可以有2方面:一是出发的快慢,一个移动的快慢。
- 本题属于两个指针出发的快慢不同。可以想到两个指针的最终位置为一个在尾结点倒数第1上,一个在倒数第k上。两者相聚k-1。则我们让快指针先走k-1步,然后俩指针同时走,则走到最后这个差距就把k-1卡出来了。
注意:
- 输入指针判空,k判0不要忘
- 若指针结点少于k个,走到最后空指针。判断当前是否为空。
程序:
// 链表结点定义
struct ListNode
{
int value;
ListNode * pNext;
};
// 找到链表的倒数第k个结点,并返回指针
ListNode * FindKthFromTail(ListNode * pHead, int k)
{
// 指针判空,数字判0
if(pHead == nullptr || k == 0)
return nullptr;
// 设置快慢指针
ListNode * pAhead = pHead;
ListNode * pBehind = nullptr;
// 快指针移动k-1步
for(int i = 0; i<k-1; ++i)
{
// 为防止结点小于k,步步加判断
if(pAhead->pNext != nullptr)
pAhead = pAhead ->pNext;
else
return nullptr;
}
// 两指针开始同时移动
pBehind = pHead;
// 快指针一直移动到尾结点
while(pAhead->pNext != nullptr)
{
pAhead = pAhead->pNext;
pBehind = pBehind ->pNext;
}
// 返回慢指针,即为倒数第k个结点
return pBehind;
}