• 问题描述:

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

struct ListNode{
	int m_nValue;
	ListNode* m_pNext;
}
  • 分析:

     要得到倒数第k个结点,也就是正数第n-k+1(其中n为结点总数)个结点,所以又有了最简单粗暴的方法:先遍历一次链表,每遍历一个结点计数器加一,最后得到n,然后第二次遍历链表,找到第n-k+1个结点,问题解决。
     当然,面试官会希望我们只遍历一次链表就得到结果,那么我们就需要定义两个指针了。我们希望遍历结束的时候,一个指针指向末尾结点,而另一个指针指向倒数第k个结点。所以,我们用第一个指针从头遍历链表,当其指向第k个结点的时候,令第二个指针指向第一个结点,然后两个指针一起向前遍历,知道第一个指针到达链表末尾,此时第二个指针所指的结点即倒数第k个结点。代码如下:

    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k)
    {
       if(pListHead == NULL || k == 0)
       	return NULL;
       
       ListNode *pAhead = pListHead;
       ListNode *pBehind = NULL;
        
       for(int i = 0; i < k-1; ++i)
       {
       	if(pAhead->m_pNext != NULL)
       		 pAhead = pAhead->m_pNext;
       	else
       		return NULL;
       }
       
       pBehind = pListHead;
       while(pAhead->m_pNext != NULL)
       {
       	pAhead = pAhead->m_pNext;
       	pBehind = pBehind->m_pNext;
       }
       return pBehind;
    }
    

    值得注意的是,我们不仅要写出代码,还要考虑代码的鲁棒性。以此题为例,我们需要考虑一下三种情况:

    • 输入的链表头指针pListHead为空指针
    • 输入的参数k为0
    • 输入的以pListHead为头结点的链表中的结点总数少于k
  • 相关题目:
    1)求链表结点的中间结点。如果链表结点的总数为奇数,则返回中间结点;如果结点总数是偶数,则返回中间两个结点中的任意一个。
    思路:依然使用两个指针,这两个指针同时从头结点开始,一个一次向后移两步,一个一次向后移一步,则当走的快的指针到达链表末尾时,走的慢的指针刚好在链表中间。
    2)判断一个单链表是否形成了环形结构。

解题思路:对于一个链表的问题,用一个指针遍历不能解决问题时,可以尝试使用两个指针来遍历链表。并让一个指针遍历的速度快一些,或者让它先在链表上走若干步。

 posted on 2017-04-24 13:13  Bill_LHR  阅读(215)  评论(0编辑  收藏  举报