题目:输入一个单向链表,输出该链表中倒数第 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: }