一、題目
力扣原題:https://leetcode-cn.com/problems/rotate-list/
二、模擬法
/**
* 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 (null == head || 0 == k) {
return head;
}
// 計算鏈表長度
int length = 0;
ListNode cur = head;
while (null != cur) {
length++;
cur = cur.next;
}
// 模擬k輪鏈表旋轉
for (int i = 0; i < (k % length); i++) {
ListNode last = head;
ListNode tmp = head;
cur = head;
while (null != cur && null != cur.next) {
last = cur;
cur = cur.next;
tmp = cur;
}
if (last != tmp) {
last.next = null;
tmp.next = head;
head = tmp;
}
}
return head;
}
}
- 基本思路:根據題目對旋轉鏈表的定義,模擬鏈表旋轉的過程即可。
- 時間複雜度:遍歷計算鏈表長度O(n),旋轉鏈表的時間複雜度爲O(kn),通過取模運算可以降低外層的循環次數。
- 最優:O(n)。k % length <= 1時,僅需要進行一輪旋轉即可;
- 最差:O(n^2)。k % length = n - 1時,需要進行n - 1輪旋轉;
- 平均:O(n^2)。
- 空間複雜度:O(1)
二、尋找分割點
/**
* 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 (null == head || 0 == k) {
return head;
}
// 計算鏈表長度
int length = 0;
ListNode cur = head;
while (null != cur) {
length++;
cur = cur.next;
}
// 計算偏移量
int step = length - (k % length);
if (step == length || step <= 0) {
return head;
}
// 確認分割點
cur = head;
for (int i = 0; i < step - 1; i++) {
cur = cur.next;
}
// 斷鏈
ListNode first = cur.next;
cur.next = null;
// 找到第二段鏈表的末尾元素
cur = first;
while (null != cur && null != cur.next) {
cur = cur.next;
}
// 重新組鏈
cur.next = head;
head = first;
return head;
}
}
/**
* 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 (null == head || 0 == k) {
return head;
}
// 鏈表成環,並計算其長度
int length = 0;
ListNode cur = head;
while (null != cur && null != cur.next) {
length++;
cur = cur.next;
}
cur.next = head;
length++;
// 計算步長
int step = length - (k % length) - 1;
// 定位分割點
cur = head;
for (int i = 0; i < step; i++) {
cur = cur.next;
}
// 斷鏈
ListNode first = cur.next;
cur.next = null;
return first;
}
}
- 基本思路:模擬鏈表旋轉,可以發現旋轉相當於將鏈表從某個分割點分割並進行重組。以上展示了兩種不同的思路,可以先分割後重組鏈表,也可以先將鏈表成環後分割,本質上沒有什麼差別。
- 時間複雜度:O(n)。遍歷計算鏈表長度O(n),斷鏈和組鏈的時間複雜度爲O(n)。
- 空間複雜度:O(1)。
四、總結
- 鏈表旋轉具有邏輯上的重複語義,可以通過取模運算降低問題的規模;
- 可以通過node.next = null斷鏈;