1. 程式人生 > >LeetCode(初級演算法)陣列篇---旋轉陣列

LeetCode(初級演算法)陣列篇---旋轉陣列

題目

將包含 n 個元素的陣列向右旋轉 k 步。

例如,如果 n = 7 , k = 3,給定陣列 [1,2,3,4,5,6,7] ,向右旋轉後的結果為 [5,6,7,1,2,3,4]

注意:

儘可能找到更多的解決方案,這裡最少有三種不同的方法解決這個問題。

[顯示提示]

提示:

要求空間複雜度為 O(1)

解析

  • 做這道題之前需要知道,k是以一個數組長度為迴圈週期。

    所以無論是什麼方法,都應該在開始時就完成k=k%nums.length;

方法一

  • 第一種方法是最為直接的,按照邏輯上對旋轉怎麼理解,就讓程式怎麼執行
  • 需要一個臨時變數
  • 這種方法簡單易懂,但==效率很低==

Example:每旋轉1次的執行過程

1)先將最後一個儲存到臨時變數
1   2   3   4   5   6   7   8    [8]---臨時變數
2)位移
_   1   2   3   4   5   6   7   [8]---臨時變數
3) 將臨時變數放到第一個
8   1   2   3   4   5   6   7

程式碼

public class Solution {
    @Test
    public void rotate(int[] nums, int k) {
        k = k % nums.length;

        for
(int count = 0; count < nums.length; count++) { //執行趟數 int temp = nums[nums.length - 1]; for (int j = nums.length - 1; j > 0; j--) { nums[j] = nums[j - 1]; } nums[0] = temp; } } }

方法二

  • 第二種方法用得是正則表示式,通過StringBuffer將旋轉後的結果新增入緩衝區,再用Matcher進行篩選

  • 這種方法比較適用於==陣列長度較大的旋轉==,時間複雜度較高,但空間複雜度較低

    public class Solution3 {
    private static String REGEX = "[+-]?\\d+";
    
    public void rotate(int[] nums, int k) {
        k=k%nums.length;
    
        StringBuffer str = new StringBuffer();
        int index = nums.length-k; 
          //time在這裡作為趟數,也作為偏移量
        for(int time=0;time<nums.length;time++) {  
            str.append(nums[(index + time) %nums.length]);
            str.append(' '); 
        }
           //編譯正則表示式
        Pattern p =Pattern.compile(REGEX); 
          //進行匹配
        Matcher m =p.matcher(str);
        int i=0;
        while(m.find()) {
            nums[i++]= Integer.valueOf(str.substring(m.start(),m.end()));
        }       
    }
    }
    

方法三

  • 第三種方法,是通過呼叫System.arraycopy和使用Arrays.copyOfRange完成,對陣列內容的複製和移動
  • 這種方法執行==速度很快(System.arraycopy 是 本地方法)==,但是空間複雜度會比較高

程式碼

public void rotate(int[] nums, int k) {
        k=k%nums.length;
        // 返回 下標 為 nums.length-k到最後一個元素的子陣列temp
        int temp[] = Arrays.copyOfRange(nums,nums.length-k ,nums.length); 
         // 將剩餘的元素複製到旋轉後的位置
        System.arraycopy(nums, 0, nums, k, nums.length-k);
         // 將temp複製到nums的開頭
        System.arraycopy(temp, 0,nums , 0, k);
    }

圖解

1) 初始狀態
nums:   1   2   3   4   5   6   7   8
k:  3
2) 取出子集
nums:   1   2   3   4   5   6   7   8
temp:   6   7   8
3) 將剩餘的元素複製到旋轉後的位置
nums:   1   2   3   1   2   3   4   5
temp:   6   7   8
4) 將temp複製到nums的開頭
nums:   6   7   8   1   2   3   4   5

拓展

陣列的複製

  • System.arrayscopy(源陣列,起始位置,目標陣列,起始位置,複製長度)—-本地方法

​ *可以複製到自己身上

​ Eg:System.arrayscopy(obj,0,obj,3,3):表示數組裡的前三個字元向右移動3個位置

  • Arrays.copyOf(目標陣列,新的長度)—– 返回新陣列

  • Arrays.copyOfRang(目標陣列,起始位置,結束位置)—–返回新陣列

與System.arrayscopy不同的是:==複製區間是從起始位置,到結束位置的前一個元素==