《剑指offer》面试题22:链表中倒数第k个结点

  更多剑指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");
    }
}

猜你喜欢

转载自blog.csdn.net/tianzez/article/details/80157352