剑指offer面试题22——链表中倒数第k个节点

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

 

思路:

        如果可以遍历两次的话,这道题就很简单,第一次遍历链表得到链表的长度length,然后从前往后查找第length-k+1个节点即可。还有一种方法可以只需要遍历一次就得到结果。首先定义两个指针,让第一个指针从头开始移动k-1步,第二个指针保持不动(为空),从第k个节点开始,第二个指针和第一个指针同时开始遍历,由于两个指针始终保持在k-1的距离,当第一个节点走到尾节点的时候,第二个指针刚好指向倒数第k个节点。如下图所示:

剑指offer面试题22——链表中倒数第k个节点_第1张图片

          但是这道题其实还隐含了很多陷阱,比如输入链表的指针为空,或者k=0,无符号的k-1等于4294967295,不等于-1。还有链表的元素不足k的情况,如果无法处理这些情况,代码的鲁棒性就会很差,这也是面试官所看重的,所以在写代码的时候千万要考虑周到,并且能够处理这些特殊情况。 

代码:

struct ListNode
{
	int m_nValue;
	ListNode* m_pNext;
};

ListNode* FindKthToTail(ListNode* pListHead, unsigned int k)
{
	if (pListHead == nullptr || k == 0)
		return;
	ListNode*pAhead = pListHead;
	ListNode*pBehind = nullptr;
	for (unsigned int i = 0; i < k; ++i)
	{
		if (pAhead->m_pNext != 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;
}

复习:

       题目倒是不难,但是要注意输入的特殊情况,比如k和i是无符号的会好一些,还有空指针以及链表长度不够k的特殊情况判定。

二刷代码:

struct ListNode
{
	int m_value;
	ListNode* m_pNext;
};

ListNode* FindNumber(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->m_pNext != nullptr)
			pAhead = pAhead->m_pNext;
		else {
			return nullptr;
		}

	}
	pBehind = pListHead;
	if (pAhead->m_pNext != nullptr)
	{
		pAhead = pAhead->m_pNext;
		pBehind = pBehind->m_pNext;
	}
	return pBehind;
}


 

你可能感兴趣的:(剑指offer)