題目鏈接:189. 輪轉數組 - 力扣(LeetCode)
?思路一
我們可以在進行每次輪轉的時候,先將數組的最后一個數據的值存儲起來,接著將數組中前n-1個數據依次向后移,最后將存儲起來的值賦給數組中的第一個數據。
先將數組中最后的一個元素的值存到變量tmp中,如下圖
接著將數組中前n-1個數據依次向后移,如下圖?
最后再將tmp中的值賦值給nums[0],如下圖?
以上圖是表示一次輪轉的,如果還要輪轉,重復上面的操作。
代碼實現
public void rotate(int[] nums, int k) {for(int i=0;i<k;i++){int tmp=nums[nums.length-1];//將前n-1個元素向后移for(int j=nums.length-1;j>0;j--){nums[j]=nums[j-1];}nums[0]=tmp;}}
當我們提交以上代碼時,會發現不成功。
思路是對的,但是上面代碼時間復雜度為O(kn),太復雜了,超出了題目的時間限制。?
思路二
造成思路一時間復雜度太大的原因是:?思路一中有兩個循環,一個循環是數組右旋的次數,另一個循環要將數組中的元素全部遍歷一遍,這樣當右旋次數足夠多,數組中的元素很多時,效率就很低了。
思路二是k次旋轉法。
下面以旋轉次數為3來講解,也就是k=3
先將數組全部旋轉一遍,如下圖
再以下標為0為起始點和下標為(k%nums.length)-1為終點來旋轉,如下圖
?最后以下標為(K%數組長度)為起始點和以下標為(數組長度-1)為終點來旋轉數組。
這樣就完成了數組的3次右旋。
代碼實現
public void reverse(int[] nums,int start,int end){while(start<end){int tmp=nums[start];nums[start]=nums[end];nums[end]=tmp;start++;end--;}}public void rotate(int[] nums, int k) {reverse(nums,0,nums.length-1);reverse(nums,0,(k%nums.length)-1);reverse(nums,k%nums.length,nums.length-1);}
思路三
我們可以創建一個新的數組,將原數組中的數據按照數組旋轉之后的的位置放置到新數組中對應的位置。最后我們再將新數組復制到原數組中就行了。
有一個公式:((i+k)%數組的長度) 的值 是 原數組中下標為i的數據 在 新數組中的位置。
其中i為原數組中數據的小標,k為旋轉次數。?
理解公式:
假如數組向右旋轉k,也就是讓數組中的數據向右移動k個位置,但是如果k大于數組長度,就會越界,所以我們要%數組的長度。因為如果旋轉的次數超過數組的長度,也就是旋轉k次的效果和k減去數組的長度次的效果是一樣的。
代碼實現
public void rotate(int[] nums, int k) {int n=nums.length;//創建一個新數組jianint[] newNums=new int[n];//將原數組中的數據放到新數組中for(int i=0;i<n;i++){newNums[(i+k)%n]=nums[i];}//將新數組復制到原數組System.arraycopy(newNums,0,nums,0,n);}