输入一个单向链表,输出该链表中倒数第 k 个结点。链表的倒数第0 个结点为链表的尾指针。

题目:输入一个单向链表,输出该链表中倒数第 k 个结点。链表的倒数第0 个结点为链表的尾指针。

分析:

由于题目指明是单向链表,自然不能反向输出倒数第k个节点,除非你先逆置单链表。虽然也是一种做法,但个人感觉比较麻烦。在此,提供两种思路:

【思路一】

我们首先遍历单链表,得到单链表中节点的个数n(注意,头结点不含数据元素,所以在此不将其算为一个链表节点),然后再次遍历单链表,从第一数据元素节点(即头结点的下一个节点)开始的第n-k+1个节点即为所求的倒数第k个节点,只需向后移动n-k次指针。这样我们一共遍历了两次链表。虽然时间复杂度是O(n),但是如果链表的节点数比较多,比如不能一次将数据读入到内存,将会非常耗时。

参考代码:

1: LinkNode * FindReverserNode(LinkNode* head,int k)    
2: {    
3:     if(head==NULL || head->next==NULL)    
4:         return NULL;    
5:     int NodeCount=0;    
6:     LinkNode*first=head;    
7:     while(head->next!=NULL)    
8:     {    
9:         first=first->next;   
10:         NodeCount++;   
11:     }   
12:     if(NodeCount<k)   
13:         return NULL;   
14:     first=head->next;   
15:     for(int i=0;i<NodeCount-k;i++)   
16:          first=first->next;   
17:     return first;   
18: }

【思路二】

我们可以设置两个指针,使它们相距k-1,这样当后一个指针指向最后一个节点时,前一个指针刚好指向倒数第k个指针。这样,我们只需遍历一遍链表即可。参考代码如下:

  1: LinkNode* FindReverseNode(LinkNode* head, int k) 
  2: { 
  3:       if(head == NULL || head->next==NULL) 
  4:             return NULL; 
  5:  
  6:       LinkNode *first = head->next;//跳过头结点,指向第一个数据元素 
  7:       LinkNode *second = head->next;//跳过头结点,指向第一个数据元素 
  8:  
  9:       for(int i = 1; i < k; i++)//向前移动k-1个距离 
 10:       { 
 11:             if(second->next != NULL) 
 12:                   second = second->next; 
 13:             else 
 14:             { 
 15:                   return NULL; 
 16:             } 
 17:       } 
 18:  
 19:       while(second->next != NULL) 
 20:       { 
 21:             second = second->next; 
 22:             first= first->next; 
 23:       } 
 24:  
 25:       return first; 
 26: } 
 27: 

另外,类似题目还有:输入一个单向链表。如果该链表的结点数为奇数,输出中间的结点;如果链表结点数为偶数,输出中间两个结点前面的一个。

思路是类似的,同样设置两个指针first,second,每次,first向后移动一个节点,second向后移动两个节点,直到second不能再向后移动时,first指向的节点即为所求节点。参考代码:

  1: LinkNode *getMidNode(LinkNode *head) 
  2: { 
  3:     if(head == NULL || head->next==NULL) 
  4:         return NULL; 
  5:  
  6:     LinkNode *first=head->next,*second=head->next; 
  7:  
  8:     while(second->next != NULL && second->next->next != NULL) 
  9:     { 
 10:          first = first->next; 
 11:          second = second->next->next; 
 12:     } 
 13:  
 14:     return first; 
 15: }
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值