【剑指offer】面试题15、链表中倒数第 K 个结点
题目:输入一个链表,输出该链表中倒数第 k 个结点。本题从 1 开始计数,即链表的尾结点为倒数第一个结点。例如一个链表有 6 个结点,从头结点开始它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个结点是值为 4 的结点。
链表结点定义如下:
typedef struct Node { int m_nValue; struct Node *m_pNext; }ListNode, *pListNode;
方法一、遍历两次链表
第一次统计出链表中结点的个数;
第二次就能找到倒数第 k 个结点。
方法二、利用快慢指针
快慢指针:一个指针走在前面,另一个指针走在后面。(额,略显粗糙)
具体做法为:我们定义两个指针pFast、pSlow。
1、第一个指针pFast从链表的头指针开始遍历,并向前走 k-1,第二个pSlow指针保持不动;
2、从第 k 步开始, 第一个指针和第二个指针同时移动;
由于两个指针的距离始终保持为 k-1,当第一个指针 pFast 指针到达链表的尾结点时,第二个指针 pSlow 指针正好是倒数第 k 个结点。
注意:要考虑链表的长度是否少于 k 个。
测试代码如下:
1 #include "stdio.h" 2 #include "stdlib.h" 3 4 #define N 10 5 6 // deleteNode.c 7 #include "stdio.h" 8 #include "stdlib.h" 9 10 #define N 10 11 12 typedef struct Node 13 { 14 int m_nValue; 15 struct Node *m_pNext; 16 }ListNode, *pListNode; 17 18 void createList(ListNode **pHead, int len) 19 { 20 ListNode *pTail = NULL; 21 22 while(len--) 23 { 24 ListNode *pNew = (ListNode*)malloc(sizeof(ListNode)); 25 pNew->m_nValue = rand()%100; 26 pNew->m_pNext = NULL; 27 28 if(*pHead == NULL) 29 { 30 *pHead = pNew; 31 pTail = pNew; 32 } 33 else 34 { 35 pTail->m_pNext = pNew; 36 pTail = pNew; 37 } 38 } 39 } 40 41 void printList(ListNode *pHead) 42 { 43 while(pHead != NULL) 44 { 45 printf("%3d ", pHead->m_nValue); 46 pHead = pHead->m_pNext; 47 } 48 printf("\n"); 49 } 50 51 ListNode *findKthToTail(ListNode *pHead, int k) 52 { 53 if(!pHead || k <= 0) 54 return NULL; 55 56 ListNode *pFast = pHead; 57 int i; 58 for(i = 1; i < k; ++i) 59 { 60 if(pFast->m_pNext != NULL) 61 pFast = pFast->m_pNext; 62 else 63 return NULL; 64 } 65 ListNode *pSlow = pHead; 66 67 while(pFast->m_pNext != NULL) 68 { 69 pFast = pFast->m_pNext; 70 pSlow = pSlow->m_pNext; 71 } 72 return pSlow; 73 } 74 75 int main(int argc, char const *argv[]) 76 { 77 ListNode *pHead = NULL; 78 79 createList(&pHead, N); 80 printf("Before: "); 81 printList(pHead); 82 83 ListNode *kthNode = findKthToTail(pHead, 3); 84 printf("The Kth Node: %d\n", kthNode->m_nValue); 85 86 return 0; 87 }
本文完。