一.什么是旋转数组
注意什么是旋转,就是往右旋转就是往右整体迁移一步,超过数组的部分就重新在从数组的头开始。类似一个环上的数据整体迁移。
这样就是右旋转了一步,就是整体数字往下一个索引移动一步,超过部分又回到了开头的部分
如下图:
二.题目
其实英文原题是指的尽量使用原地算法,这里翻译错了,这个题目为啥要每次都移动一步呢,因为他只用一个数组,不能用其他的数组,所以每次移动一步,其他k>1不论多少都能这样去实现。
解法1-暴力法
思考
*就是按照题目的意思,每次把最后一个拿出来,然后把前面的数往后挪一位
*注意下面不是两个元素交换,而是挪动元素。
*就是旋转k次,每次旋转一个元素
*每次旋转一个元素怎么旋转,就是先把最后一位元素取出来,作为一个pre,把第一个元素值拿出给temp暂存,然后把第一个元素的值等于这个pre,最后把第一个元素值作为pre
* 把第二个元素拿出给temp暂存,把第二个元素等于这个pre,最后把第二个元素值作为pre
*这样就起到了一个挪动的效果。
代码
class Solution {
/**
*就是按照题目的意思,每次把最后一个拿出来,然后把前面的数往后挪一位
*注意下面不是两个元素交换,而是挪动元素。
*就是旋转k次,每次旋转一个元素
*每次旋转一个元素怎么旋转,就是先把最后一位元素取出来,作为一个pre,把第一个元素值拿出给temp暂存,然后把第一个元素的值等于这个pre,最后把第一个元素值作为pre
* 把第二个元素拿出给temp暂存,把第二个元素等于这个pre,最后把第二个元素值作为pre
*这样就起到了一个挪动的效果。
*/
public void rotate(int[] nums, int k) {
//相当于做了一个优化,就是如果旋转次数大于数组长度了那旋转着旋转着又旋转回去了,比如nums=[1,2,3],k=3,旋转3次就相当于没旋转,旋转4次,相当于,又重头开始了
k=k%nums.length;
for(int i=0;i<k;i++){
int pre = nums[nums.length-1];
for(int j=0;j<nums.length;j++){
int temp = nums[j];
nums[j] = pre;
pre = temp;
}
}
}
}
解法2-翻转
思考
下面的例子观察到只需要把数组逆序排一遍,然后把0-2逆序一次,剩下的逆序一次即可。
也就是先逆序整个数组,然后把0到(k-1)逆序,最后把k到length-1逆序。
代码
class Solution {
/**
*下面的例子观察到只需要把数组逆序排一遍,然后把0-2逆序一次,剩下的逆序一次即可。
*也就是先逆序整个数组,然后把0到(k-1)逆序,最后把k到length-1逆序。
*/
public void rotate(int[] nums, int k) {
int l = nums.length;
k=k%l;
reverse(nums,0,l-1);
reverse(nums,0,k-1);
reverse(nums,k,l-1);
}
public void reverse(int[] nums,int start,int end){
while(start<end){
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
}
解法3-利用环去做
思考
利用环去做
思考:就是把数组看成一个环,比如k=2,那么1会从0移动到2,3会从2移动到4,5会从4移动到6,7从6移动到0。暂且称之这一系列操作为一组。
然后2从1移动到3,4从3移动到5,6从5移动到8。
由于这种特殊的替换操作,不论k等于多少,里面元素都只会做一次移动操作,也就是如果这个移动操作等于这个数组长度的时候就是整个数组的数都移动过了,这时候就可以将结果return了。
每一组操作完,strat往前一步,来操作下一组数。
代码
class Solution {
public void rotate(int[] nums, int k) {
int l = nums.length;
k = k%l;
int start = 0;
int current = start;
int pre = nums[start];
int count = 0;
while(true){
//这儿是从start每k个一组,的一组
//因为是dowhile,所以刚开始的时候current==start是可以执行的,但是当下一次等于的时候说明这一组做到头了
//所以下一次相等的时候就跳出循环了
do{
//当前元素即将挪过去的位置索引
int nextIndex = (current+k)%l;
int temp = nums[nextIndex];
nums[nextIndex] = pre;
count++;
pre = temp;
current = nextIndex;
if(l==count){
return;
}
//为真继续循环
}while(current != start);
//当前组完了,就start的下一个
start++;
current=start;
pre = nums[start];
}
}
}