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. 三种方法都要掌握,但面试时尽量用第三种
相关推荐
咩咦34 分钟前
C++学习笔记02:cin 和 cout 输入输出
c++·学习笔记·cin·输入输出·cout
咩咦39 分钟前
C++学习笔记05:引用和常引用
c++·学习笔记·引用·const·常引用
香蕉鼠片1 小时前
算法过程中不会的
开发语言·c++
阿旭超级学得完1 小时前
C++11包装器(function和bind)
java·开发语言·c++·算法·哈希算法·散列表
li星野1 小时前
位运算 & 数学 & 高频进阶九题通关(Python + C++)
c++·python·学习·算法
jerryinwuhan1 小时前
hello算法,简单讲(1)
算法·排序算法
y = xⁿ1 小时前
20天速通LeetCodeday15:BFS广度优先搜索
算法·宽度优先
400分1 小时前
吃透RAG核心-----语义检索与关键字检索底层原理
算法·架构
目黑live +wacyltd1 小时前
算法备案:常见驳回原因与应对策略
人工智能·算法
磊 子2 小时前
多态类原理+四种类型转换+异常处理
开发语言·c++·算法