更多剑指offer面试习题请点击:《剑指offer》(第二版)题集目录索引
1. 题目:
输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个结点是值为4的结点。
2. 解题思路:
采用快慢指针法,快指针pFast和慢指针pSlow开始都指向链表头结点。
1. 让快指针pFast先走k-1步;
2. 然后快慢指针同时走。
3. 当快指针走到尾节点时,慢指针刚好走到倒数第k个节点。
ps:注意边界条件
3. < Code >
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k)
{
if (pListHead == nullptr || k == 0) // 1. 链表不能为空且k最小值为1
{
return nullptr;
}
ListNode* pFast = pListHead;
ListNode* pSlow = pListHead;
unsigned int i = 0;
for (; i < k - 1; ++i)
{
if (pFast->m_pNext != nullptr)
{
pFast = pFast->m_pNext;
}
else // 2. k值不能超过链表长度
{
return nullptr;
}
}
while (pFast->m_pNext != nullptr) // 3. 快指针pFast走到尾节点停止(不是走到nullptr)
{
pFast = pFast->m_pNext;
pSlow = pSlow->m_pNext;
}
return pSlow; // 4. 返回慢指针pSlow
}
4. < TestCode>
// 测试要找的结点在链表中间
void Test1()
{
printf("Test1 starts:\n");
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5);
PrintList(pNode1);
printf("Find the third node of the countdown: ");
ListNode* pNode = FindKthToTail(pNode1, 3);
PrintListNode(pNode);
DestroyList(pNode1);
}
// 测试要找的结点是链表的尾结点
void Test2()
{
printf("Test2 starts:\n");
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5);
PrintList(pNode1);
printf("Find the first node of the countdown: ");
ListNode* pNode = FindKthToTail(pNode1, 1);
PrintListNode(pNode);
DestroyList(pNode1);
}
// 测试要找的结点是链表的头结点
void Test3()
{
printf("Test3 starts:\n");
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5);
PrintList(pNode1);
printf("Find the fifth node of the countdown: ");
ListNode* pNode = FindKthToTail(pNode1, 5);
PrintListNode(pNode);
DestroyList(pNode1);
}
// 测试空链表
void Test4()
{
printf("Test4 starts:\n");
printf("nullptr\n");
printf("Find the hundredth node of the countdown: ");
ListNode* pNode = FindKthToTail(nullptr, 100);
PrintListNode(pNode);
}
// 测试输入的第二个参数大于链表的结点总数
void Test5()
{
printf("Test5 starts:\n");
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5);
printf("expected result: nullptr.\t");
ListNode* pNode = FindKthToTail(pNode1, 6);
PrintListNode(pNode);
DestroyList(pNode1);
}
// 测试输入的第二个参数为0
void Test6()
{
printf("Test6 starts:\n");
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode2);
ConnectListNodes(pNode2, pNode3);
ConnectListNodes(pNode3, pNode4);
ConnectListNodes(pNode4, pNode5);
PrintList(pNode1);
printf("Find the sixth node of the countdown: ");
ListNode* pNode = FindKthToTail(pNode1, 0);
PrintListNode(pNode);
DestroyList(pNode1);
}
int main()
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
system("pause");
return 0;
}
5. < TestResult>
6. < BasicCode >
ListNode* CreateListNode(int value) //创建节点
{
ListNode* newNode = new ListNode;
newNode->m_nValue = value;
newNode->m_pNext = nullptr;
return newNode;
}
void ConnectListNodes(ListNode* pNode1, ListNode* pNode2) //链接节点
{
pNode1->m_pNext = pNode2;
}
void DestroyList(ListNode* pListHead) //销毁链表
{
if (pListHead == nullptr)
return;
ListNode* pCurNode = pListHead->m_pNext;
while (pCurNode != nullptr)
{
delete pListHead;
pListHead = pCurNode;
pCurNode = pCurNode->m_pNext;
}
delete pListHead;
pListHead = nullptr;
}
void PrintList(ListNode* pListHead) //打印链表
{
ListNode* pCurNode = pListHead;
while (pCurNode != nullptr)
{
printf("%d -> ", pCurNode->m_nValue);
pCurNode = pCurNode->m_pNext;
}
printf("nullptr\n");
}
void PrintListNode(ListNode* pNode) //打印节点
{
if (pNode != nullptr)
{
printf("%d\n\n", pNode->m_nValue);
}
else
{
printf("nullptr\n\n");
}
}