LeetCode热题100--189

189. 轮转数组

题目链接

题目描述

给定一个整数数组 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]

解题思路

关键点

  1. 注意处理 k 可能大于数组长度的情况,需要使用取模运算
  2. 需要原地修改数组,不能使用额外的数组(虽然方法1和方法2用了额外空间,但题目要求O(1)空间)

三种解法对比

方法一:双倍数组法

cpp 复制代码
void rotate(vector<int>& nums, int k) {
    int n = nums.size();
    k = k % n;  // 处理k大于n的情况
    vector<int> nums1(nums);  // 复制原数组
    nums1.insert(nums1.end(), nums.begin(), nums.end());  // 拼接两份
    nums.clear();
    nums.insert(nums.begin(), nums1.begin() + n - k, nums1.begin() + 2 * n - k);
}

思路解析:

  1. 先把原数组复制一份,然后拼接到自己后面
  2. 从新数组的 n-k 位置开始,取 n 个元素
  3. 用这个子数组替换原数组

示例:

复制代码
nums = [1,2,3,4,5], k=2, n=5
nums1 = [1,2,3,4,5,1,2,3,4,5]
从位置 n-k=3 开始取5个:nums1[3]=4, [4]=5, [5]=1, [6]=2, [7]=3
结果:[4,5,1,2,3]

复杂度:

  • 时间复杂度:O(n),需要遍历数组
  • 空间复杂度:O(n),需要额外的数组空间

方法二:额外数组法

cpp 复制代码
void rotate(vector<int>& nums, int k) {
    int n = nums.size();
    vector<int> nums1(n);
    for(int i = 0; i < n; i++) {
        nums1[(i + k) % n] = nums[i];
    }
    nums.assign(nums1.begin(), nums1.end());
}

思路解析:

  1. 创建一个和原数组同样大小的新数组
  2. 遍历原数组,将每个元素放到新数组的 (i+k)%n 位置
  3. 用新数组替换原数组

示例:

复制代码
nums = [1,2,3,4,5], k=2, n=5
i=0: nums1[(0+2)%5=2] = 1 → nums1[2]=1
i=1: nums1[(1+2)%5=3] = 2 → nums1[3]=2
i=2: nums1[(2+2)%5=4] = 3 → nums1[4]=3
i=3: nums1[(3+2)%5=0] = 4 → nums1[0]=4
i=4: nums1[(4+2)%5=1] = 5 → nums1[1]=5
nums1 = [4,5,1,2,3]

复杂度:

  • 时间复杂度:O(n),需要遍历数组
  • 空间复杂度:O(n),需要额外的数组空间

方法三:三次反转法(最优解)

cpp 复制代码
void rotate(vector<int>& nums, int k) {
    int n = nums.size();
    k = k % n;
    reverse(nums.begin(), nums.end());          // 反转整个数组
    reverse(nums.begin(), nums.begin() + k);     // 反转前k个
    reverse(nums.begin() + k, nums.end());      // 反转剩下的
}

思路解析:

  1. 先反转整个数组
  2. 再反转前k个元素
  3. 最后反转剩下的n-k个元素

示例:

复制代码
nums = [1,2,3,4,5], k=2, n=5
1. 整体反转: [5,4,3,2,1]
2. 反转前k=2个: [4,5,3,2,1]
3. 反转剩下的n-k=3个: [4,5,1,2,3]

数学原理:

向右旋转k位,相当于把后k个元素移到前面。通过三次反转可以巧妙地实现这个操作:

  • 整体反转:把末尾元素放到开头
  • 反转前k个:恢复被反转的尾部顺序
  • 反转剩下的:恢复被反转的头部顺序

复杂度:

  • 时间复杂度:O(n),三次反转操作
  • 空间复杂度:O(1),原地修改,不需要额外空间

总结对比

方法 时间复杂度 空间复杂度 优点 缺点
双倍数组法 O(n) O(n) 思路直观,容易理解 需要额外O(n)空间
额外数组法 O(n) O(n) 逻辑简单清晰 需要额外O(n)空间
三次反转法 O(n) O(1) 最优解,原地修改 需要理解反转原理

注意事项

  1. 必须处理 k > n 的情况,通过 k = k % n 取模
  2. 题目要求原地修改,但有些方法用了额外空间
  3. 三种方法都要掌握,但面试时尽量用第三种
相关推荐
8Qi87 小时前
LeetCode 75:颜色分类(荷兰国旗问题)—— Java 题解 ✅
java·算法·leetcode·指针·排序
888CC++9 小时前
如何在 C 语言中进行程序调试?
前端·javascript·算法
pluviophile_s10 小时前
数据结构:第2讲:线性表
数据结构·笔记
(●—●)橘子……10 小时前
力扣第503场周赛练习理解
python·学习·算法·leetcode·职场和发展·周赛
明志数科12 小时前
4D时序标注技术详解:让机器人理解连续动作的数据基础
java·算法·机器人
feng_you_ying_li12 小时前
C++复习二,继承与多态
c++
小小de风呀12 小时前
de风——【从零开始学C++】(十一):list的基本使用和模拟实现
开发语言·c++·list
KaMeidebaby12 小时前
卡梅德生物技术快报|原核表达系统工艺优化:包涵体重折叠 + 分子筛纯化实现功能 RBD 高效制备,附全参数配置
前端·人工智能·算法·数据挖掘·数据分析
陌路2013 小时前
C++高级进阶--夯实进阶基础(1)
开发语言·c++