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; } };