XingHuiSamaの宝藏之地
首页项目归档照片墙音乐灵境说说杂谈友链关于
封面

Leetcode一百题——轮转数组

2026-04-14 09:41:23
# Leetcode
# C++
# 题解
# 算法

给定一个整数数组 nums,将数组中的元素向右轮转 k个位置,其中 k是非负数。

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 105

我首先想到的是类似于剪下来,然后贴到后面去这样的算法,然后发现还可以通过翻转做。

解法一

1. 算法核心思想

采用辅助数组的策略实现数组轮转 。整体思路上,借助一个临时数组 temp 来完成元素位置的调度 。通过计算出轮转的切割分界点,先将尾部因轮转会移动到前方的元素放入临时数组,再将原数组头部的元素顺接至其后方,最终将临时数组的内容覆盖回原数组 。

2. 执行逻辑梳理

  • 处理轮转周期: 数组轮转具有周期性。代码开头通过 if (k > nums.size()) 结合取模运算 k % nums.size(),去除了超出数组长度的多余轮转次数 。这保证了后续的轮转步数处于合法范围内,避免了数组寻址越界 。
  • 确定分界点: 创建辅助数组 temp 后,计算出变量 mid = nums.size() - k 。该变量代表原数组在执行轮转时的绝对分界线 。
  • 尾部元素前调: 第一个 for 循环从分界线 mid 遍历至原数组末尾 。这一步将受轮转影响需要移动到数组前方的元素,按顺序写入 temp 数组的头部区域 。
  • 头部元素后移: 第二个 for 循环从原数组索引 0 遍历至 mid 。将原数组前半部分未发生越界的数据,顺延写入至 temp 数组已有数据的后方 。
  • 最终数据回填: 此时 temp 数组已完成所有元素的重新排列。最后一个 for 循环遍历将 temp 数组的所有数据重新赋值给原数组 nums,以此完成原地修改的题目要求 。
class 轮转数组 {
public:
    void rotate(vector<int>& nums, int k) {

        if (k > nums.size()) {
            k = k % nums.size();
        }

        vector<int> temp = vector<int>(nums.size(),0);
        int mid = nums.size()-k;

        int j = 0;
        for (int i = mid; i < nums.size(); i++) {
            temp[j] = nums[i];
            j++;
        }

        for (int i = 0;i < mid;i++) {
            temp[j] = nums[i];
            j++;
        }

        for (int i = 0;i < nums.size(); i++) {
            nums[i] = temp[i];
        }
    }
};

3. 复杂度分析

  • 时间复杂度: O(n)。代码中虽然包含了三个 for 循环,但它们属于并列关系,分别遍历了数组的不同区间 。整体相当于对数组进行了线性的遍历,时间效率符合要求 。
  • 空间复杂度: O(n)。算法在函数内部申请了一个与原数组规模相同的 temp 数组,因此额外消耗了随数组规模线性增长的内存空间 。

解法二

1. 算法核心思想

采用“三次反转”的策略实现数组的原地轮转。整体思路上,通过对数组的不同区间进行三次翻转动作,达到元素位置重新排列的目的 。这种写法不需要开辟额外的辅助数组,能够在空间复杂度为 O(1) 的情况下完成数组轮转 。

2. 执行逻辑梳理

  • 处理轮转周期: 数组轮转具有周期性。代码开头通过 if (k > nums.size()) 结合取模运算 k % nums.size(),去除了超出数组长度的多余轮转次数 。这保证了后续的轮转步数处于合法范围内,避免了数组寻址越界。
  • 整体反转: 第一次调用 reverse 将整个数组头尾对调 。此时,原本位于尾部需要轮转到前方的元素被移动到了数组的前部,但其内部顺序是倒序的;原本位于头部的元素被移动到了后部,内部顺序也是倒序的。
  • 前部反转: 第二次调用 reverse 将数组前 k 个元素再次反转 。这一步将前部元素的内部顺序恢复为原数组中的相对顺序 。
  • 尾部反转: 第三次调用 reverse 将数组后面剩余的元素反转回来 。这一步将后部元素的内部顺序恢复正常,至此完成整个数组的轮转 。
class 轮转数组 {
//翻面做法
public:
    void rotate(vector<int>& nums, int k) {

        if (k > nums.size()) {
            k = k % nums.size();
        }

        reverse(nums.begin(), nums.end());

        reverse(nums.begin(), nums.begin() + k);

        reverse(nums.begin() + k, nums.end());

    }
};

3. 复杂度分析

  • 时间复杂度: O(n)。算法共执行了三次反转操作,总体相当于对数组进行线性的遍历,时间效率符合要求。
  • 空间复杂度: O(1)。该解法全程直接在原数组上进行元素修改,没有任何额外的内存开销,实现了原地修改 。
avatar

XingHuiSama

在代码、学术与分子动力学模拟间穿梭的普通人。近期正埋头于 GROMACS 模拟研究与神经网络计算。

RECOMMENDED

GROMACS 2025 分子动力学模拟初探2222

2026-03-24 07:00:45

Computational Chemistry Tool 工具二介绍

2026-04-01 07:00:23

Leetcode一百题——字母异位词分组

2026-04-07 15:34:18

Table of Contents