面试经典算法系列之链表8 -- 旋转链表

面试经典算法14-旋转链表

LeetCode.61
公众号:阿Q技术站

问题描述

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

示例 1:

img

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

示例 2:

img

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

提示:

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

思路

  1. 计算链表的长度,并找到链表的尾节点,同时将链表形成一个循环链表。
  2. 计算实际需要移动的步数 k = k % 链表长度,因为如果 k 大于链表长度,实际上是重复一整轮的旋转操作。
  3. 找到新链表的尾节点和头节点的位置,并将尾节点指向 nullptr,形成新的链表。

图解

这里根据示例一给大家做一个图解。

  1. 计算链表的长度,并找到链表的尾节点,同时将链表形成一个循环链表。

image-20240222000033781

  1. 计算实际需要移动的步数 k = k % 链表长度,因为如果 k 大于链表长度,实际上是重复一整轮的旋转操作。

image-20240222000046133

  1. 找到新链表的尾节点和头节点的位置,并将尾节点指向 nullptr,形成新的链表

image-20240222000109474

即:

image-20240222000250210

  1. 返回newHead即可。

参考代码

C++
#include <iostream>

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if (!head || !head->next || k == 0) return head; // 如果链表为空或只有一个节点,或者 k 为 0,直接返回原链表

        int length = 1; // 计算链表长度
        ListNode* tail = head;
        while (tail->next) {
            tail = tail->next;
            length++;
        }

        k = k % length; // 计算实际需要移动的步数

        if (k == 0) return head; // 如果 k 等于 0,直接返回原链表

        ListNode* newTail = head;
        for (int i = 0; i < length - k - 1; i++) {
            newTail = newTail->next;
        }

        ListNode* newHead = newTail->next;
        newTail->next = nullptr;
        tail->next = head;

        return newHead;
    }
};

// 创建链表
ListNode* createList(std::vector<int>& nums) {
    if (nums.empty()) return nullptr;
    ListNode* head = new ListNode(nums[0]);
    ListNode* cur = head;
    for (int i = 1; i < nums.size(); ++i) {
        cur->next = new ListNode(nums[i]);
        cur = cur->next;
    }
    return head;
}

// 输出链表
void printList(ListNode* head) {
    ListNode* cur = head;
    while (cur) {
        std::cout << cur->val << " ";
        cur = cur->next;
    }
    std::cout << std::endl;
}

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5};
    int k = 2;

    // 创建链表
    ListNode* head = createList(nums);

    // 旋转链表
    Solution solution;
    ListNode* newHead = solution.rotateRight(head, k);

    // 输出旋转后的链表
    printList(newHead);

    return 0;
}
Java
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if (head == null || k == 0) return head;

        // 计算链表长度并找到尾节点
        int len = 1;
        ListNode tail = head;
        while (tail.next != null) {
            tail = tail.next;
            len++;
        }

        // 计算实际需要旋转的次数
        k = k % len;
        if (k == 0) return head; // 如果 k 是链表长度的倍数,不需要旋转

        // 找到倒数第 k+1 个节点,作为新的尾节点
        ListNode newTail = head;
        for (int i = 0; i < len - k - 1; i++) {
            newTail = newTail.next;
        }

        // 旋转链表
        ListNode newHead = newTail.next;
        newTail.next = null; // 断开环
        tail.next = head; // 将原链表接到尾部

        return newHead;
    }
}
Python
class Solution:
    def rotateRight(self, head: ListNode, k: int) -> ListNode:
        if not head or k == 0:
            return head

        # 计算链表长度并找到尾节点
        len = 1
        tail = head
        while tail.next:
            tail = tail.next
            len += 1

        # 计算实际需要旋转的次数
        k = k % len
        if k == 0:
            return head  # 如果 k 是链表长度的倍数,不需要旋转

        # 找到倒数第 k+1 个节点,作为新的尾节点
        new_tail = head
        for _ in range(len - k - 1):
            new_tail = new_tail.next

        # 旋转链表
        new_head = new_tail.next
        new_tail.next = None  # 断开环
        tail.next = head  # 将原链表接到尾部

        return new_head
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值