标签:
题目:输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人都习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1, 2, 3, 4, 5, 6。这个链表的倒数第3个结点是值为4的结点。链表结点定义如下:
typedef struct ListNode { int val; struct ListNode *p_next; }NODE, *PNODE;
为了找到倒数第k个结点,很自然的就可以想到先找到链表的尾结点,然后从后往前找1第k个结点。然而从链表结点的结构情况来看,它是一个单链表,所以这种方法直接就out了。
所以我们马上就又想到了,假设链表结点总数为n,那么倒数第k个结点不就是第 n-k+1 个结点喽!既然如此,我们只需先把整个链表遍历一遍,统计出总的结点个数,然后在从头开始遍历,找出第 n-k+1 个结点就ok了。
上边这个方法效率只能说是还行,但因为它需要把链表遍历两次,这样不是做了很多无用功嘛。所以我们要想着优化一下。怎么才能在只遍历一次的情况下,就找到倒数第k个结点呢?
like this:
定义两个指针,第一个指针从链表的头结点开始向后走k-1步,第二个指针不动;从第k步开始,第二个指针也开始从链表的头指针处向后遍历。由于这两个指针的距离始终保持着k-1的距离,所以当第一个指针走到了链表的尾结点时,第二个指针自然的就指向了倒数第k个结点。如图所示,这是一个链表,有两个指针指向它的头结点:
这里再假设我们要查找倒数第3个结点,也就是3这个结点。那么接下来就是让right指针向后移动 3-1 步,变成这样:
right现在指向了结点3,接下来,left指针和right指针同时开始右移,直到right指向尾结点,如下:
这时Right指向了尾结点,同时的,left也已经指向了倒数第k个结点。
另外,还有几点要注意的是,如果传进来的链表是一个空指针怎么办?传进来的k小于0怎么办?k大于总结点数怎么办?这些情况都需要进行处理。理清了总体思路,接下来就可以开始写代码了:
PNODE find_Kth_to_tail(PNODE head, int k) { PNODE left = NULL; PNODE right = NULL; int i = 0; assert(head); if (k <= 0) return NULL; left = right = head; for (i = 0; (i < k-1) && (NULL != right->p_next); i++) { right = right->p_next;; } if (i != k-1) return NULL; while (NULL != right->p_next) { left = left->p_next; right = right->p_next; } return left; }void distroy(PNODE head) { PNODE tmp = NULL; while (NULL != head) { tmp = head; head = head->p_next; free(tmp); } }
写完代码一定不要忘记测试哟!#include <stdio.h> #include <stdlib.h> #include <assert.h> typedef struct ListNode { int val; struct ListNode *p_next; }NODE, *PNODE;int main() { PNODE p1 = (PNODE)malloc(sizeof(NODE)); PNODE p2 = (PNODE)malloc(sizeof(NODE)); PNODE p3 = (PNODE)malloc(sizeof(NODE)); PNODE p4 = (PNODE)malloc(sizeof(NODE)); PNODE ret = NULL; p1->val = 1; p1->p_next = p2; p2->val = 2; p2->p_next = p3; p3->val = 3; p3->p_next = p4; p4->val = 4; p4->p_next = NULL; ret = find_Kth_to_tail(p1, 5); if (ret) printf("%d\n", ret->val); else printf("没找到\n"); distroy(p1); return 0; }
还有一些同类型的题目,比如返回链表的中间结点,判断链表是不是形成了环形结构等,都可以用这种两个指针的思路来实现。
当我们用一个指针遍历链表不能解决问题的时候,可以尝试用两个指针来遍历链表。可以让其中一个指针遍历的速度快些,比如一次让这个指针走两步,或者干脆让它先走若干步。(《剑指offer》)
标签:
原文地址:http://blog.csdn.net/qq_33724710/article/details/51344286