目錄
描述
給定一個鏈表,旋轉鏈表,將鏈表每個節點向右移動 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)\)