1. 程式人生 > >[CareerCup] 2.2 Kth to Last Element of Linked List 連結串列的倒數第k個元素

[CareerCup] 2.2 Kth to Last Element of Linked List 連結串列的倒數第k個元素

2.2 Implement an algorithm to find the kth to last element of a singly linked list.

這道題讓我們求連結串列中倒數第k個元素,LeetCode中相類似的題目有Kth Largest Element in an Array 陣列中第k大的數字 和 Kth Smallest Element in a BST 二叉搜尋樹中的第K小的元素。但那兩道題和這題又不一樣,首先這道題是要在連結串列中操作,連結串列的特點就是不能通過下標來直接訪問元素,而且要知道連結串列長度的話只能遍歷,當然如果這道題先遍歷一遍知道了長度,再來找倒數第k個就沒啥挑戰,也不是這道題考察的初衷。這道題可以用遞迴和非遞迴兩種方法來解。我們先來看看遞迴的方法,方法是先無腦遞迴到最末尾,然後開始回去,每回一個計數器累加1,直到回到k返回節點即可,此方法的時間複雜度和空間複雜度均為O(n),程式碼如下:

解法一:

// Recursion
class Solution {
public:
    ListNode *kthToLast(ListNode *head, int k) {
        int i = 0;
        return kthToLastDFS(head, k, i);
    }
    ListNode *kthToLastDFS(ListNode *head, int k, int &i) {
        if (!head) return head;
        ListNode *node = kthToLastDFS(head->next, k, i);
        
++i; if (i == k) return head; return node; } };

下面我們來看非遞迴的方法,這種方法就巧妙的多,需要用兩個指標,其中一個指標先向前走k個,然後兩個指標同時走,當先走那個到達末尾時,另外一個指標指向的元素就是倒數第k個,時間複雜度為O(n),空間複雜度為O(1),程式碼如下:

解法二:

// Non-recursion
class Solution {
public:
    ListNode *kthToLast(ListNode *head, int k) {
        ListNode 
*pre = head, *cur = head; for (int i = 0; i < k; ++i) { if (cur) cur = cur->next; } while (cur) { cur = cur->next; pre = pre->next; } return pre; } };