《剑指offer》第二十二题:链表中倒数第k个结点

Posted 源周率

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《剑指offer》第二十二题:链表中倒数第k个结点相关的知识,希望对你有一定的参考价值。

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

#include <cstdio>
#include "List.h"

ListNode* FindKthToTail(ListNode* pListHead, unsigned int k)
{
    //鲁棒性测试 1.空链表 2.k为0(无意义)
    if (pListHead == nullptr || k == 0)
        return nullptr;

    ListNode* pListAhead = pListHead;
    ListNode* pListAfter = pListHead;
    //前面的指针先走 k-1步
    for (int i = 0; i < k - 1; ++i)
    {
        if (pListAhead->m_pNext != nullptr)
            pListAhead = pListAhead->m_pNext;
        else
            return nullptr;
    }
    //然后后面指针跟上
    while (pListAhead->m_pNext != nullptr)
    {
        pListAhead = pListAhead->m_pNext;
        pListAfter = pListAfter->m_pNext;
    }
    return pListAfter;
}
技术图片
// ====================测试代码====================
// 测试要找的结点在链表中间
void Test1()
{
    printf("=====Test1 starts:=====
");
    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: 4.
");
    ListNode* pNode = FindKthToTail(pNode1, 2);
    PrintListNode(pNode);

    DestroyList(pNode1);
}

// 测试要找的结点是链表的尾结点
void Test2()
{
    printf("=====Test2 starts:=====
");
    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: 5.
");
    ListNode* pNode = FindKthToTail(pNode1, 1);
    PrintListNode(pNode);

    DestroyList(pNode1);
}

// 测试要找的结点是链表的头结点
void Test3()
{
    printf("=====Test3 starts:=====
");
    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: 1.
");
    ListNode* pNode = FindKthToTail(pNode1, 5);
    PrintListNode(pNode);

    DestroyList(pNode1);
}

// 测试空链表
void Test4()
{
    printf("=====Test4 starts:=====
");
    printf("expected result: nullptr.
");
    ListNode* pNode = FindKthToTail(nullptr, 100);
    PrintListNode(pNode);
}

// 测试输入的第二个参数大于链表的结点总数
void Test5()
{
    printf("=====Test5 starts:=====
");
    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.
");
    ListNode* pNode = FindKthToTail(pNode1, 6);
    PrintListNode(pNode);

    DestroyList(pNode1);
}

// 测试输入的第二个参数为0
void Test6()
{
    printf("=====Test6 starts:=====
");
    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.
");
    ListNode* pNode = FindKthToTail(pNode1, 0);
    PrintListNode(pNode);

    DestroyList(pNode1);
}

int main(int argc, char* argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();

    return 0;
}
测试代码

分析:两个指针将遍历次数减少为一次。

技术图片
/*
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* pListAhead = pListHead;
        ListNode* pListAfter = pListHead;
        
        for (int i = 0; i < k-1; ++i)
        {
            if (pListAhead->next != nullptr)
                pListAhead = pListAhead->next;
            else
                return nullptr;
        }
        
        while (pListAhead->next != nullptr)
        {
            pListAhead = pListAhead->next;
            pListAfter = pListAfter->next;
        }
        return pListAfter;
    }
};
牛客网提交代码

 

以上是关于《剑指offer》第二十二题:链表中倒数第k个结点的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer十四之链表中倒数第k个结点

剑指offer 14.链表中倒数第k个结点

《剑指Offer》题目:链表中倒数第k个结点

剑指offer编程-链表中倒数第k个结点

剑指Offer-14.链表中倒数第k个结点(C++/Java)

剑指Offer 链表中倒数第k个结点