题目描述:给你一个数组,将数组中的元素向右轮转k个位置,其中k是非负数。
为什么会想到取余数?
对于循环数组而言,移动到数组末尾之后要想继续从头开始移动,其实就是移动余数步数。
思路1:循环数组取余法
额外开辟一个数组,将原数组移动后的元素直接放入新开辟的数组中,其中,涉及到数组的取模运算。
- 当i+k<n,直接放入i+k的位置即可(i+k%n);
- 当i+k>=n,此时说明已经走到数组的末尾,需要从数组的开头进行移动(i+k%n)。
代码实现:
//循环数组取余法
public void rotate(int[] nums,int k){
//开辟一个和原数组大小相同的新数组
int[] temp=new int[nums.length];
//将原数组元素向右移动k步之后置入temp数组中
for(int i=0;i<nums.length;i++){
temp[(i+k)%nums.length]=nums[i];
}
//此时temp数组中存储了移动后的元素,写回nums数组
for (int i = 0; i <nums.length ; i++) {
nums[i]=temp[i];
}
}
思路2:反转数组法
空间复杂度为O(1)的原地算法。
整体反转的目的是将nums2数组调整到nums1的前面;
子数组的反转是为了还原原来元素的相对顺序。
代码实现:
//2.反转数组法
public void rotate(int[] nums,int k){
//k有可能超过数组长度,将多余的步数取余处理掉
k%=nums.length;
//1.整体数组反转,将需要移动到前面的元素通过整体反转nums2移动到nums1的前面
reverse(nums,0,nums.length-1);
//2.子数组分别反转,负负得正,将子数组内部的元素还原为反转前的元素状态
reverse(nums,0,k-1);
reverse(nums,k,nums.length-1);
}
public void reverse(int[] nums,int left,int right){
while(left<right){
int temp=nums[left];
nums[left]=nums[right];
nums[right]=temp;
left++;
right--;
}
}