一、问题描述:
给定一个整数数组 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]
二、解题思路:
- 首先对 k 取余是为了处理 k 大于数组长度的情况,确保旋转的步数在一个周期内。
- 思路1,使用额外的数组空间:
①首先,为了避免出现数组越界问题,创建了一个长度为原数组两倍的新数组 newnums。
②然后,将原始数组 nums 中的元素依次复制到新数组中,同时在新数组的后半部分也复制一份原数组的内容,这样实现了循环移动的效果。
③最后,根据旋转后的位置,从新数组中将旋转后的元素复制回原数组 nums。 - 思路2,数组翻转:
定义了一个辅助函数 reserve,该函数用来反转数组中指定范围内的元素,不需要额外空间。通过三次调用 reserve 函数,实现了数组的旋转操作:
①第一次调用 reserve 函数反转整个数组,在这之后,原数组中的元素顺序被颠倒。
②第二次调用 reserve 函数反转前 k 个元素,将前 k 个元素恢复到正确的顺序。
③第三次调用 reserve 函数反转剩下的元素,将剩下的元素恢复到正确的顺序。
三、代码示例:
- 使用额外的数组
java
//时间复杂度为 O(n)
class Solution {
public void rotate(int[] nums, int k) {
k = k % (nums.length);//对k取余,右移nums.length位是原数组
int[] newnums = new int[2*nums.length];
for(int i = 0; i < nums.length; i++){
newnums[i] = nums[i];
newnums[i + nums.length] = nums[i];
}
for(int i = 0; i < nums.length; i++){
nums[i] = newnums[nums.length - k + i];
}
}
}
- 时间复杂度分析:
在这段代码中,主要涉及两个循环:
①第一个循环用于复制原数组到新数组,时间复杂度为 O(n),其中 n 为原数组的长度。
②第二个循环用于将旋转后的元素复制回原数组,同样为 O(n)。
因此,总体时间复杂度为 O(n),其中 n 为原数组的长度。空间复杂度为 O(n)。
2.数组翻转
java
//时间复杂度为 O(n)
class Solution {
public void rotate(int[] nums, int k) {
k = k % (nums.length);//对k取余,右移nums.length位是原数组
reserve(nums, 0, nums.length - 1);
reserve(nums, 0, k - 1);
reserve(nums, k, nums.length - 1);
}
public void reserve(int [] nums, int l, int r){
while(l < r){
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
l++;
r--;
//System.out.println(l +" "+ r );
}
}
}
- 时间复杂度分析:
在这段代码中,主要涉及了三次调用 reserve 函数,而 reserve 函数本身的时间复杂度为 O(n/2),其中 n 为待反转元素的个数。
因此,总体时间复杂度为 O(n),其中 n 为数组的长度。空间复杂度为 O(1)。