问题描述:
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]
示例 2:
输入:nums = [-1,-100,3,99], k = 2 输出:[3,99,-1,-100] 解释: 向右轮转 1 步: [99,-1,-100,3] 向右轮转 2 步: [3,99,-1,-100]
解题思路:
简单思路:
直接模拟:最直观的方式是每次将数组最后一个元素移动到第一个位置,重复 k 次。但是,这种做法的时间复杂度为 O(kn),当 k 很大时效率低下。
- 对于每个轮转操作,我们需要做的是:
- 将数组的最后一个元素保存到一个临时变量中。
- 将数组中的所有元素向后移动一位。
- 将之前保存的最后一个元素放置到数组的第一个位置。
- 这个过程需要重复 k 次。
在代码中的第一步中,为什么k需要进行取模运算?
是因为为了防止k大于数组的长度,如果k大于数组的长度,就可以理解为向右轮转又重新回到了原来的位置(相当于没动),然后再加上需要动的几个位置,所以用取模来看向右移动了几步(小于数组长度的几步).
class Solution {public void rotate(int[] nums, int k) {//第一步:确保k不超过数组的长度,超过就是相当于没动+取模动的几步k = k % nums.length;//第二步:重复k次for(int i = 0; i < k; i++){//第三步:保存最后一个元素、int lastElement = nums[nums.length - 1];//第四步:向又移动其余元素for(int j = nums.length -1;j > 0;j--){nums[j] = nums[j - 1];}//第五步:将最后一个元素放到最前面位置nums[0] = lastElement;}}
}
优秀思路:
-
反转数组(推荐):
- 先整体反转整个数组。
- 然后反转前 k 个元素。
- 最后再反转剩下的 n-k 个元素。
- 这样就能实现将数组向右轮转 k 个位置的效果,并且不需要额外的空间。
注意事项
- 如果 k 大于数组长度,则实际轮转次数应该取 k % 数组长度,因为每经过一轮完整的数组长度,数组状态会回到初始状态。
- 反转操作可以通过双指针法来实现,即从两端开始交换元素直到中间相遇。(前后交换,中间位置不动)
class Solution {public void rotate(int[] nums, int k) {//翻转三次int n = nums.length;reverse(nums, 0, n - 1);//整体翻转reverse(nums, 0, k - 1);//反转前k个reverse(nums, k, n - 1);//反转剩余部分}public void reverse(int[] nums, int start, int end){while(start < end){int temp = nums[end];nums[end] = nums[start];nums[start] = temp;start++;end--;}}}