剑指offer 题22—链表中倒数第K个节点

剑指offer 题22—链表中倒数第K个节点

题目

输入一个链表,输出该链表中倒数第K个节点。为了符合大多数人的习惯,从本题第1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次为1,2,3,4,5,6.这个链表的倒数第3个节点是值为4的节点。节点定义如下:

struct ListNode
{
    
    
	int m_nValue;
	ListNode* m_pNext;
}

思考

为了得到倒数第k个节点,最自然的想法当然是先走到尾端,再回溯K步。但是从定义可以看到,这是个单向链表。所以这样是不行的。

方法一

所以我们还是要回到头节点来。整个链表是n个节点,倒数第K个就是n-k+1个节点。关键是得到n,有了n,再从头往后走n-k+1步就可以了。如何得到n?遍历一遍,计数就能得到了。
这个办法需要遍历链表两边,第一次统计节点个数,第二次找倒数第K个节点。
那么,有没有只遍历一遍的办法呢?当然有

方法二

要实现一次遍历能完成,需要定义两个指针。
第一个指针从链表的头指针开始遍历向前走K-1步;第二个指针保持不动,从第K步开始,第二个指针也开始从链表的头指针开始遍历。
两个指针距离保持再k-1,当前面的指针走到尾节点时,后面的指针真好指向倒数第K个节点

例子

下面有个例子,一共有6个节点,找倒数第3个节点
图解如下:
在这里插入图片描述

代码

写代码之前,我们还需要去除一些特殊情况:
1、输入的pListHead为空指针。如果直接访问空指针指向的内容,会造成程序的崩溃
2、输入的以pListHead为头节点的链表的节点总数少于k。由于再循环中会再链表上向前走k-步,依旧会由于空指针问题而造成崩溃
3、输入的参数为0,由于k时一个无符号整数,再for循环中k-1不是-1,而是4294967295(0xFFFFFFFF),因此for循环执行的次数远超过我们的预计,同样会造成崩溃

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->mpNext!=nullptr)
			pAhead=pAhead->m_pNext;
		else
			return nullptr;
	}
	pBehind=pListHead;
	while(pAhead->m_pNext!=nullptr)
	{
    
    
		pAhead=pAhead->m_pNext;
		pBehind=pBehind->m_pNext;
	}
	return pBehind;
}

猜你喜欢

转载自blog.csdn.net/rjszz1314/article/details/104334787