【LeetCode題解】61_旋轉鏈表(Rotate-List)

目錄

描述

給定一個鏈表,旋轉鏈表,將鏈表每個節點向右移動 k 個位置,其中 k 是非負數。

示例 1:

輸入: 1->2->3->4->5->NULL, k = 2
輸出: 4->5->1->2->3->NULL
解釋:
向右旋轉 1 步: 5->1->2->3->4->NULL
向右旋轉 2 步: 4->5->1->2->3->NULL

示例 2:

輸入: 0->1->2->NULL, k = 4
輸出: 2->0->1->NULL
解釋:
向右旋轉 1 步: 2->0->1->NULL
向右旋轉 2 步: 1->2->0->NULL
向右旋轉 3 步: 0->1->2->NULL
向右旋轉 4 步: 2->0->1->NULL

解法:雙指針

思路

求解這道題等價於找到鏈表倒數第 k 個節點,然後將之前的所有節點放到鏈表的尾部,形成一個新的鏈表,相當於 LeetCode 第 19 題的進階版。

對於尋找單向鏈表的倒數第 \(k\) 個元素問題,可以採用雙指針的方法進行求解。

  • 令指針 p1 和指針 p2 均指向表頭,然後讓指針 p2 跳轉 \(k - 1\) 次,此時指針 p2 處於鏈表的第 \(k\) 個節點

  • 接着,讓兩個指針同時向鏈表尾部跳轉,直到指針 p2 處於鏈表的尾部,此時,指針 p1 指向的節點正是鏈表的倒數第 \(k\) 個節點

在找到倒數第 \(k\) 個節點後,只需要將指針 p2 指向鏈表頭 head、指針 p1 的前一個節點的 next 指針指向 null,最後指針 p1 就是新的鏈表的表頭。

值得注意的是,在這道題中,我們需要找到的是鏈表的倒數第 \(k+1\) 個節點,從而才能對該節點的 next 指針進行操作(指向 null)。同樣地,也需要注意一些邊界情況,比如表頭 head 爲空,k 大於鏈表長度等。

Java 實現

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        // 邊界情況處理
        if (head == null) {
            return head;
        }

        // 統計鏈表長度並對k進行取餘操作
        int length = 1;
        ListNode tmp = head;
        while (tmp.next != null) {
            tmp = tmp.next;
            ++length;
        }
        k = k % length;
        if (k == 0) {
            return head;
        }

        // 尋找倒數第k+1個節點
        ListNode p1 = head, p2 = head;
        for (int i = 0; i < k; ++i) {
            p2 = p2.next;
        }
        while (p2.next != null) {
            p1 = p1.next;
            p2 = p2.next;
        }

        // 旋轉鏈表
        ListNode newHead = p1.next;
        p1.next = null;
        p2.next = head;

        return newHead;
    }
}
// Runtime: 6 ms
// Your runtime beats 100.00 % of java submissions.

Python 實現

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def rotateRight(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        # 邊界情況處理
        if not head:
            return head
        
        # 統計鏈表的長度並對k進行取餘操作
        tmp, n = head, 1
        while tmp.next:
            tmp, n = tmp.next, n + 1
        k = k % n
        if k == 0:
            return head
        
        # 找到倒數第k+1個節點
        p1, p2 = head, head
        for i in range(k):
            p2 = p2.next
        while p2.next:
            p1 = p1.next
            p2 = p2.next
        
        # 旋轉鏈表
        new_head = p1.next
        p1.next, p2.next = None, head
        return new_head
        
# Runtime: 44 ms
# Your runtime beats 99.11 % of python3 submissions.

複雜度分析

  • 時間複雜度:\(O(n)\),其中 \(n\) 表示鏈表的長度。首先需要迭代 \(n\) 次找出鏈表的長度,接着讓指針 p2 迭代 \(k\) 次到達第 \(k+1\) 個節點的位置,最後還需要迭代 \(n-(k+1)\) 次使得兩個指針一個指向鏈表尾部,一個指向倒數第 \(k+1\) 個節點,而迭代所執行的操作的時間複雜度都是 \(O(1)\) 的,所以最後總的時間複雜度是 \(O(n)\)
  • 空間複雜度:\(O(1)\)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章