剑指Offer第15题(链表中倒数第k个结点)

(本博客旨在个人总结回顾)

题目描述:

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

链表结点定义如下:

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

解题思路:

使用两个指针A,B,将B指针移动到第K个结点,然后将A设置为头结点,将两结点同时一步一步往下一结点移动,当B结点移动到尾结点时,A结点就刚好移动到倒数第K个结点。

考虑输入的异常情况:①链表结点数少于k的情况;②k<=0的情况。③链表为NULL

目标函数:

/*
 * @name   GetKthToTail
 * @brief  获取链表的倒数第k个结点
 * @param  [in] ListNode * pListHead
 * @param  [in] int k
 * @return ListNode*
 */
 ListNode* GetKthToTail(ListNode* pListHead, int k)
{
    if (NULL == pListHead || k <= 0)
    {
        return NULL;
    }

    ListNode* pAHead = pListHead;
    ListNode* pFind = pListHead;

    //pAHead设置为第K个结点(从1开始计算)
    for (int i = 1; i < k ; i++)
    {
        if (pAHead->m_pNext != NULL)
        {
            pAHead = pAHead->m_pNext;
        }
        else
        {
            return NULL;
        }
    }

    //pAHead移动的最后一个结点
    //pFind刚好就移动至第K个结点
    while (pAHead->m_pNext != NULL)
    {
        pAHead = pAHead->m_pNext;
        pFind = pFind->m_pNext;
    }
    return pFind;
}

完整测试代码:


#include "stdafx.h"
#include <iostream>
using namespace std;

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


/*
 * @name   GetKthToTail
 * @brief  获取链表的倒数第k个结点
 * @param  [in] ListNode * pListHead
 * @param  [in] int k
 * @return ListNode*
 */
 ListNode* GetKthToTail(ListNode* pListHead, int k)
{
    if (NULL == pListHead || k <= 0)
    {
        return NULL;
    }

    ListNode* pAHead = pListHead;
    ListNode* pFind = pListHead;

    //pAHead设置为第K个结点(从1开始计算)
    for (int i = 1; i < k ; i++)
    {
        if (pAHead->m_pNext != NULL)
        {
            pAHead = pAHead->m_pNext;
        }
        else
        {
            return NULL;
        }
    }

    //pAHead移动的最后一个结点
    //pFind刚好就移动至第K个结点
    while (pAHead->m_pNext != NULL)
    {
        pAHead = pAHead->m_pNext;
        pFind = pFind->m_pNext;
    }
    return pFind;
}


int _tmain(int argc, _TCHAR* argv[])
{
    //测试1题描述例子
    ListNode* pHead1 = new ListNode();
    pHead1->m_nValue = 1;
    ListNode* pTmp = new ListNode();
    pTmp->m_nValue = 2;
    pHead1->m_pNext = pTmp;

    pTmp->m_pNext = new ListNode();
    pTmp = pTmp->m_pNext;
    pTmp->m_nValue = 3;

    pTmp->m_pNext = new ListNode();
    pTmp = pTmp->m_pNext;
    pTmp->m_nValue = 4;

    pTmp->m_pNext = new ListNode();
    pTmp = pTmp->m_pNext;
    pTmp->m_nValue = 5;

    pTmp->m_pNext = new ListNode();
    pTmp = pTmp->m_pNext;
    pTmp->m_nValue = 6;

    ListNode* pKNode = GetKthToTail(pHead1, 3);
    if (pKNode != NULL)
    {
        cout << "测试例子1:倒数第3个结点值为" << pKNode->m_nValue << endl;
    }    
    else
    {
        cout << "测试例子1:不存在该结点" << endl;
    }

    //测试2链表结点数小于K
    pKNode = GetKthToTail(pHead1, 7);
    if (pKNode != NULL)
    {
        cout << "测试例子2:倒数第7个结点值为" << pKNode->m_nValue << endl;
    }
    else
    {
        cout << "测试例子2:不存在该结点" << endl;
    }

    //测试3链表结点数等于1,k=1
    pKNode = GetKthToTail(pTmp, 1);
    if (pKNode != NULL)
    {
        cout << "测试例子3:倒数第1个结点值为" << pKNode->m_nValue << endl;
    }
    else
    {
        cout << "测试例子3:不存在该结点" << endl;
    }

    //测试4:K <= 0
    pKNode = GetKthToTail(pTmp, 0);
    if (NULL == pKNode)
    {
        cout << "测试例子4:不存在该结点" << endl;
    }
    pKNode = GetKthToTail(pTmp, -1);
    if (NULL == pKNode)
    {
        cout << "测试例子4:不存在该结点" << endl;
    }

    //测试5:链表NULL
    pKNode = GetKthToTail(NULL, 1);
    if (NULL == pKNode)
    {
        cout << "测试例子5:不存在该结点" << endl;
    }

    system("pause");
    return 0;
}

运行结果:

剑指Offer第15题(链表中倒数第k个结点)

上一篇:在北京三年java开发经验月薪16k,如何在四年经验时要到20k? - 暗灭的回答 - 知乎


下一篇:剑指Offer第17题(合并两个排序的链表)