题目描述
给定一个整数数组 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
题目作答
最简便方法的思想: 解决这个问题最巧妙且高效的方法是使用数组翻转。这个方法是空间复杂度为 O(1) 的原地算法。
思路可以分为三步,以 nums = [1,2,3,4,5,6,7] 和 k = 3 为例:
处理 k 值: 首先,为了防止 k 大于数组长度而进行不必要的旋转,我们让 k 对数组长度取模。k = k % nums.size()。如果 k 是 7,旋转 7 次等于没旋转;如果 k 是 8,旋转 8 次等于旋转 1 次。所以 k=3 % 7 = 3。
翻转整个数组: 将数组的所有元素进行翻转。
[1,2,3,4,5,6,7] -> [7,6,5,4,3,2,1]
翻转前 k 个元素: 将数组的前 k 个元素(也就是 [0, k-1] 区间)进行翻转。
[7,6,5,4,3,2,1] -> [5,6,7,4,3,2,1]
翻转后 n-k 个元素: 将数组中剩下的元素(也就是 [k, n-1] 区间)进行翻转。
[5,6,7,4,3,2,1] -> [5,6,7,1,2,3,4]
经过这三步翻转,数组就完成了向右轮转 k 个位置的操作,得到了最终结果。这个方法的思想在于通过整体和局部的翻转,巧妙地将数组末尾的 k 个元素移动到了数组的开头。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
// 获取数组的长度
int n = nums.size();
// 如果数组为空或只有一个元素,则无需旋转
if (n == 0) { return; }
// 步骤 1: 处理 k 值,使其在 [0, n-1] 范围内
k = k % n;
// 步骤 2: 翻转整个数组
std::reverse(nums.begin(), nums.end());
// 步骤 3: 翻转前 k 个元素
std::reverse(nums.begin(), nums.begin() + k);
// 步骤 4: 翻转后 n-k 个元素
std::reverse(nums.begin() + k, nums.end());
}
};