1. 程式人生 > >【LeetCode題解】61_旋轉連結串列(Rotate-List)

【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)\)