链表中倒数第k个节点

【题目描述】

输入一个链表,输出该链表中倒数第k个结点。
【解题思路】
为了实现只遍历一次就能找到倒数第k个节点,我们可以定义两个指针(俗称“快慢指针”)。第一个指针从链表的头结点开始遍历向前走k-1,第二个指针保持不动;从第k步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离始终保持在k-1,当第一个指针到达链表的末尾时,第二个指针刚好走到倒数第k个节点。
 
理解:两个指针的间距从开始位置处随着指针的移动到达末尾位置一直保持在k-1,这样当尾指针到达末尾成为倒数第一个节点的时候,k-1位置的节点刚好成为倒数第k个节点。
 
注意:
快慢指针
注意边界和异常条件判断
【代码实现】
 1 /*
 2 struct ListNode {
 3     int val;
 4     struct ListNode *next;
 5     ListNode(int x) :
 6             val(x), next(NULL) {
 7     }
 8 };*/
 9 class Solution {
10 public:
11     ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
12         if(pListHead==NULL||k==0)
13             return NULL;
14         ListNode* pAhead=pListHead;
15         ListNode* pBehind;
16         for(unsigned int i=0;i<k-1;i++)
17         {
18             if(pAhead->next!=NULL)
19                 pAhead=pAhead->next;
20             else
21                 return NULL;
22         }
23 
24         pBehind=pListHead;
25         while(pAhead->next!=NULL)
26         {
27             pAhead=pAhead->next;
28             pBehind=pBehind->next;
29         }
30         return pBehind;
31     }
32 };
【举一反三】
1、求链表的中间节点:如果链表中节点总数为奇数,返回中间节点;如果节点总数为偶数,返回中间节点中的任意一个。
解题思路:定义两个指针,同时从链表头结点出发,慢指针一次走一下,快指针一次走两步,这样当快指针到达链表末尾的时候,慢指针刚好到达链表的中间位置。
代码实现:
 1 /*
 2 struct ListNode {
 3     int val;
 4     struct ListNode *next;
 5     ListNode(int x) :
 6             val(x), next(NULL) {
 7     }
 8 };*/
 9 class Solution {
10 public:
11     ListNode* FindMiddle(ListNode* pListHead) {
12          if( pListHead==NULL)//头结点为空,直接返回
13                 return NULL;
14         if(pListHead->next=NULL||pListHead->next->next==NULL)//只有一个或者两个节点,直接返回头结点
15                 return pListHead;
16         ListNode* pAhead=pListHead;
17         ListNode* pBehind=pListHead;
18         while(pAhead&&pAhead->next)
19         {    
20                pAhead=pAhead->next->next;
21                pBehind= pBehind->next;
22         }
23         return pBehind;
24     }
25 };
思考:同理可以引申出找到链表1/n位置处的节点,只要让快指针每次走n步,慢指针每次走1步,保持n:1的比例即可。
 
2、有序链表寻找中位数
解题思路:
 
代码实现:
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
 int * FindMiddle(ListNode* pListHead) {     
    if( pListHead==NULL)//头结点为空,直接返回
                return false;
    ListNode* pAhead,pBehind;
    pAhead=pBehind=pListHead;
    while (pAhead&&pBehind) 
   { 
  if (pAhead->next==NULL) 
      return pBehind ->val; 
  else if (pAhead->next!= NULL && pAhead->next->next== NULL) 
      return (pBehind ->val + pBehind ->next->val)/2; 
  else 
  { 
      pAhead= pAhead->next->next; 
      pBehind = pBehind ->next; 
  } 
 }
    }
};
3、判断一个单链表是否形成了环形结构。
解题思路:定义两个指针,同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步。如果走得快的指针追上了走得慢的指针,那么链表就是环形结构;而如果快指针走到了链表的末位都没有追上走得慢的指针,那么链表就不是环形结构。
代码实现:
 1 /*
 2 struct ListNode {
 3     int val;
 4     struct ListNode *next;
 5     ListNode(int x) :
 6             val(x), next(NULL) {
 7     }
 8 };*/
 9 class Solution {
10 public:
11    bool  isExitsLoop(ListNode* pListHead) {
12          if( pListHead==NULL)//头结点为空,直接返回
13                 return false;
14         ListNode* pAhead,pBehind;
15         pAhead=pBehind=pListHead;
16         while(pAhead&&pAhead->next)
17         {
18                 pAhead=pAhead->next->next;
19                 pBehind=pBehind->netx;
20                  if(pAhead==pBehind)
21                        return true;             
22          }
23         return false;
24     }
25 };
进一步思考:如果存在环,如何判断环的入口位置?
代码实现:
 1 /*
 2 struct ListNode {
 3     int val;
 4     struct ListNode *next;
 5     ListNode(int x) :
 6             val(x), next(NULL) {
 7     }
 8 };*/
 9 class Solution {
10 public:
11   ListNode  findLoopPoint(ListNode* pListHead) {
12          if( pListHead==NULL)//头结点为空,直接返回
13                 return false;
14         ListNode* pAhead,pBehind;
15         pAhead=pBehind=pListHead;
16         while(pAhead&&pAhead->next)
17         {
18                 pAhead=pAhead->next->next;
19                 pBehind=pBehind->netx;
20                  if(pAhead==pBehind)
21                        break;             
22          }
23         if(pAhead==NULL||pAhead->next==NULL)
24             return NULL;
25         ListNode* pList=pListHead;
26         while(pListHead!=pBehind)
27         {
28             pList=pList->next;
29             pBehind=pBehind>next;     
30          }
31         return  pList;//或者 return  pBehind;
32     }
33 };

 

转载于:https://www.cnblogs.com/lou424/p/5028596.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值