LeetCode 第61题:旋转链表

74 阅读4分钟

LeetCode 第61题:旋转链表

题目描述

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

难度

中等

题目链接

点击在LeetCode中查看题目

示例

示例 1:

示例1 输入:head = [1,2,3,4,5], k = 2 输出:[4,5,1,2,3]

示例 2:

示例2 输入:head = [0,1,2], k = 4 输出:[2,0,1]

提示

  • 链表中节点的数目在范围 [0, 500]
  • -100 <= Node.val <= 100
  • 0 <= k <= 2 * 10^9

解题思路

闭合成环后断开

这道题可以通过以下步骤解决:

  1. 首先计算链表长度,并找到尾节点
  2. 将尾节点与头节点相连,形成环
  3. 找到新的断开点,即倒数第k个节点的前一个节点
  4. 断开环,返回新的头节点

关键点:

  1. 处理k大于链表长度的情况
  2. 注意k为0或链表为空的边界情况
  3. 计算实际需要移动的步数
  4. 正确找到断开点的位置

具体步骤:

  1. 遍历链表得到长度n和尾节点tail
  2. 计算实际需要移动的步数k = k % n
  3. 如果k为0,直接返回原链表
  4. 将尾节点与头节点相连
  5. 移动到新的断开点
  6. 断开环并返回新的头节点

图解思路

算法步骤分析表

步骤操作链表状态说明
初始-1->2->3->4->5原始链表
计算长度遍历1->2->3->4->5长度为5
形成环连接1->2->3->4->5->1首尾相连
找断点移动1->2->3->4->5->1在3处断开
最终断开4->5->1->2->3完成旋转

状态/情况分析表

情况输入输出说明
空链表[][]特殊情况
k=0[1,2,3][1,2,3]无需旋转
k=len[1,2,3][1,2,3]旋转一圈

代码实现

C# 实现

public class Solution {
    public ListNode RotateRight(ListNode head, int k) {
        // 处理特殊情况
        if (head == null || head.next == null || k == 0) return head;
        
        // 计算链表长度并找到尾节点
        ListNode tail = head;
        int length = 1;
        while (tail.next != null) {
            tail = tail.next;
            length++;
        }
        
        // 计算实际需要移动的步数
        k = k % length;
        if (k == 0) return head;
        
        // 将链表首尾相连
        tail.next = head;
        
        // 找到新的断开点
        ListNode newTail = head;
        for (int i = 0; i < length - k - 1; i++) {
            newTail = newTail.next;
        }
        
        // 断开环
        ListNode newHead = newTail.next;
        newTail.next = null;
        
        return newHead;
    }
}

Python 实现

class Solution:
    def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        # 处理特殊情况
        if not head or not head.next or k == 0:
            return head
        
        # 计算链表长度并找到尾节点
        tail = head
        length = 1
        while tail.next:
            tail = tail.next
            length += 1
        
        # 计算实际需要移动的步数
        k = k % length
        if k == 0:
            return head
        
        # 将链表首尾相连
        tail.next = head
        
        # 找到新的断开点
        new_tail = head
        for i in range(length - k - 1):
            new_tail = new_tail.next
        
        # 断开环
        new_head = new_tail.next
        new_tail.next = None
        
        return new_head

C++ 实现

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        // 处理特殊情况
        if (!head || !head->next || k == 0) return head;
        
        // 计算链表长度并找到尾节点
        ListNode* tail = head;
        int length = 1;
        while (tail->next) {
            tail = tail->next;
            length++;
        }
        
        // 计算实际需要移动的步数
        k = k % length;
        if (k == 0) return head;
        
        // 将链表首尾相连
        tail->next = head;
        
        // 找到新的断开点
        ListNode* newTail = head;
        for (int i = 0; i < length - k - 1; i++) {
            newTail = newTail->next;
        }
        
        // 断开环
        ListNode* newHead = newTail->next;
        newTail->next = nullptr;
        
        return newHead;
    }
};

执行结果

  • 执行用时:84 ms
  • 内存消耗:37.8 MB

代码亮点

  1. 🎯 巧妙利用取模运算处理大k值
  2. 💡 通过闭合成环简化问题
  3. 🔍 优化了特殊情况的处理
  4. 🎨 代码结构清晰,易于理解

常见错误分析

  1. 🚫 没有处理空链表或单节点链表
  2. 🚫 k值取模计算错误
  3. 🚫 断开位置计算错误
  4. 🚫 忘记处理k为0的情况

解法对比

解法时间复杂度空间复杂度优点缺点
数组存储O(n)O(n)直观简单空间消耗大
两次遍历O(n)O(1)空间优化需遍历两次
闭合成环O(n)O(1)最优解法需要注意边界

相关题目