给定一个整数数组
nums,将数组中的元素向右轮转k个位置,其中k是非负数。
输入: 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 暴力
思路
按照题目意思来,就是往头部插入最后一个元素。
代码
function rotate(nums: number[], k: number): void {
while (k--) {
nums.unshift(nums.pop());
}
};
时空复杂度分析
时间复杂度:删除是 O(1) 的操作,但是往队头插入需要把剩下数组元素往后挪,时间开销是 O(n) ,循环 k 次,总的时间复杂度是 O(k * n)
空间复杂度:O(1)
解法2 三次翻转
思路
把整个数组翻转一次,然后把前 k 个数反转,再把剩下的数反转,就得到了反转后的数组。
但是注意,针对于 k 大于数组长度的情况,需要对 k 进行取模。
为什么取模 k %= nums.length;?
如果 k 比数组长度大,我们只需要旋转 k % nums.length 次就可以达到相同的效果,而且还不会产生空指针异常。
例子:
假设数组 nums = [1, 2, 3, 4, 5],长度为 n = 5。
如果 k = 7,这意味着你希望将数组向右旋转 7 次。
实际上旋转数组 5 次会让它恢复原状,因为旋转 5 次等于没有旋转。因此,旋转 7 次的效果与旋转 7 % 5 = 2 次是相同的。
也就是说,旋转 k 次和旋转 k % n 次是等价的,因为旋转 n 次等同于不旋转。
代码
function rotate(nums: number[], k: number): void {
const reverse = (arr: number[], start: number, end: number) => {
while (start <= end) {
const temp = arr[start];
arr[start++] = arr[end];
arr[end--] = temp;
}
}
k %= nums.length;
reverse(nums, 0, nums.length - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.length - 1);
};
时空复杂度分析
时间复杂度:O(n),总共进行了三次反转,每次反转最多遍历整个数组
空间复杂度:O(1)