本文为剑指 offer 系列第十六篇。
主要知识点为链表,就是在链表遍历的基础上进行查找操作,细心一点也没啥问题。
输入一个链表,输出该链表中倒数第k个结点。
解题思路
思路1
先将链表遍历一遍,计算总的结点的个数。
然后计算倒数第k个是从头数第几个,再遍历到这个位置。
思路2
通过双指针来解决问题。先让快指针走k步,再让两个指针一起走。
当快指针走到链表末尾的空指针时,慢指针刚好指向倒数第k个节点。
解题代码
思路1代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| /* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindKthToTail(ListNode* phead, unsigned int k) { //方法一,先跑一遍,计算总的个数。然后计算倒数第k个是正数第多少个,然后再遍历一遍。 if(!phead || k == 0) return NULL; int count = 0; ListNode* p = phead; while(p){ p = p->next; count++; } if(count < k) return NULL; p = phead; for(int i = count-k; i>0; i--){ p = p->next; } return p; } };
|
时间复杂度为O(n),辅助空间复杂度为O(1)
思路2代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: ListNode* FindKthToTail(ListNode* phead, unsigned int k) { //方法二:快慢双指针。 if(!phead || k == 0) return NULL; ListNode* fast, *slow; fast = slow = phead; for(int i = 0;i<k;i++){ fast = fast->next; if(!fast && i==k-1) return phead; if(!fast) return NULL; } while(fast){ fast = fast->next; slow = slow->next; } return slow; } };
|
或者可以用另一种写法,比较优美一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| /* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { if(!pListHead || k <= 0) return NULL; ListNode* fast = pListHead; ListNode* slow = pListHead; while(k>0 && fast){ k--; fast = fast->next; } while(fast){ fast = fast->next; slow = slow->next; } return k>0?NULL:slow; } };
|
时间复杂度为O(n),辅助空间复杂度为O(1)
以上,本题结束!