题目
想法
自己想法0
这道题说用三种解法,我先想着一种解法把。
我得解法就是新建一个数组arr,他的长度是nums的长度+k,那么直接将nums的元素移到arr的第【i+k】个位置就好,最后在复制一遍arr,就行了,说白了 就是将 nums 平移到arr上,最后将超出nums的长度的元素放回到开头部分去。
class Solution {
public void rotate(int[] nums, int k) {
if(nums.length == 1||k==0 ) return ;
while(k>nums.length) k=k-nums.length;
int arr[] = new int[nums.length+k];
for(int i = 0 ; i< nums.length;i++)
{
arr[i+k] = nums[i];
}
for(int i = 0 ; i<k;i++)
{
arr[i] = arr[i+nums.length];
}
System.arraycopy(arr,0,nums,0,nums.length);
}
}
我开始写的时候,没有第一二行的if和while语句,老出错,只通过了26个测试案例,后来想了想 ,才知道在这里出现了问题,加上while就好了,因为你的k大于nums的长度时,就相当于又回到了原来的位置而已。这点开始没想到。
进阶想法1(超时)
第二个我想着直接在原数组上进行修改,但是原数组修改值一直在变,所以不能使用这样的方法。
看看评论中如何使用O(1)的空间复杂度吧。
第二种 ,使用一个temp 占用最后一个位置空间,然后将所有的都右移一位,最后再将temp赋值给nums[0]即可。
class Solution {
public void rotate(int[] nums, int k) {
if(nums.length == 1||k==0 ) return ;
while(k>nums.length) k=k-nums.length;
int n = nums.length;
for(int i = 0 ; i<k;i++)
{
int temp = nums[n-1];
for(int j=n-1;j>0;j--)
{
nums[j] = nums[j-1];
}
nums[0] = temp;
}
}
}
这样 空间复杂度也算1,但是呢,两个for循环 ,确实超时了。
进阶想法2
第二种方式是一直交换的方式。
class Solution {
public void rotate(int[] nums, int k) {
int n =nums.length;
k=k%n;
reverse(nums,0,n-1);
reverse(nums,0,k-1);
reverse(nums,k,n-1);
}
public void reverse(int[] nums,int start,int end)
{
while(start<end)
{
int temp = nums[start];
nums[start] = nums[end];
start++;
nums[end] = temp;
end--;
}
}
}
这个代码一开始可能都没看懂为什么这样交换,我在评论区找到了答案。
感谢小甜甜。
思路:此题可以采用头插法,一个一个的移动。但是有种更加简单的选择数组的方式。
我们可以采用翻转的方式,比如12345经过翻转就变成了54321,这样已经做到了把前面的数字放到后面去,
但是还没有完全达到我们的要求,比如,我们只需要把12放在后面去,
目标数组就是34512,与54321对比发现我们就只需要在把分界线前后数组再进行翻转一次就可得到目标数组了。
所以此题只需要采取三次翻转的方式就可以得到目标数组,首先翻转分界线前后数组,再整体翻转一次即可。此题面试常考,大家可以记一下此方法。
这道题 说是面试经常考的题目,所以需要记下来呀。
进阶想法3
class Solution {
public void rotate(int[] nums, int k) {
int n =nums.length;
k=k%n;
for(int start = 0;start<nums.length&&k!=0;n-=k,start+=k,k%=n)
{
for(int i = 0 ; i< k ; i ++)
{
int temp =nums[start+i];
nums[start+i] = nums[nums.length-k+i];
nums[nums.length-k+i]=temp;
}
}
}
}
这个方法我放在idea里面进行debug查看过程,看了过程,但还是不好理解。
不仅需要注意for
循环里面的start变化,n k变换,还有 nums[start+i] = nums[nums.length-k+i];这个nums的交换位置也需要变换,所以感觉有点难记,不好理解。
这个时间复杂度O(n),空间复杂度O(1);
进阶想法4
也是一种交换方法
class Solution {
public void rotate(int[] nums, int k) {
reswap(nums,k,0,nums.length);
}
//递归
public void reswap(int nums[],int k,int start,int length)
{
k %=length;
if(k!=0)
{
for(int i = 0 ; i<k;i++)
{
swap(nums,start+i,nums.length-k+i);
}
reswap(nums,k,start+k,length-k);
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
感觉这个方法和进阶方法3有点相似,我也试着idea里debug了一下。
感觉还是不太好理解。
总结
原来旋转数组里有这么多方法,太妙了,先把基础的自己的想法做会,然后再把那个第二个方法弄懂,这是必须要会的,这个底下评论说常考呢,而且不难好理解,先掌握这两个吧,第三个第四个我看着不太理解,以后回过头来再看看有没有长进把,明天再研究,今天先去理个发。希望我可以快快的把数组中剩下的10道题做完。