1. 程式人生 > >LeetCode-探索-初級-陣列-旋轉陣列-java

LeetCode-探索-初級-陣列-旋轉陣列-java

  旋轉陣列

給定一個數組,將陣列中的元素向右移動 個位置,其中 是非負數。

示例 1:

輸入: [1,2,3,4,5,6,7]k = 3
輸出: [5,6,7,1,2,3,4]
解釋:
向右旋轉 1 步: [7,1,2,3,4,5,6]
向右旋轉 2 步: [6,7,1,2,3,4,5]
向右旋轉 3 步: [5,6,7,1,2,3,4]

示例 2:

輸入: [-1,-100,3,99]k = 2
輸出: [3,99,-1,-100]
解釋: 
向右旋轉 1 步: [99,-1,-100,3]
向右旋轉 2 步: [3,99,-1,-100]

說明:

  • 儘可能想出更多的解決方案,至少有三種不同的方法可以解決這個問題。
  • 要求使用空間複雜度為 O(1) 的原地演算法。

題目讓我們至少使用三種方法,我們就使用三種方法吧~


方法一:

還記得我們交換兩個int的程式碼嗎?

int temp = a1;

a1 = a2;

a2 = temp;

是這樣吧~

我們以nums=[1, 2, 3, 4, 5, 6, 7],k=3為例

第一次變換:1 2 3 1(4) 5 6 7

第二次變換:1 2 3 1(4) 2(5) 6 7

第三次變換:1 2 3 1(4) 2(5) 3(6) 7

第四次變換:1 2 3 1(4) 2(5) 3(6) 4(7)

我們可以看出:我們需要一個k長度的陣列儲存中間因為1 2 3覆蓋掉的4 5 6;可以看出,在第四次變換中,我們的4又重新派上了用場。

程式碼如下:

public void rotate(int[] nums, int k) {
        if (k == nums.length || k == 0 || nums.length == 1)
            return ;
        k = k % nums.length;
        int[] tempArray = new int[k];  //store the temp elements
        for (int i = 0; i < k; i++)
            tempArray[i] = nums[i];
        //init tempArray
        int temp = 0;
        int index = 0;
        int tempIndex = 0;
        for (int i = 0; i < nums.length; i++) {
            index = (i + k) % nums.length;
            temp = nums[index];
            nums[index] = tempArray[tempIndex];
            tempArray[tempIndex] = temp;
            tempIndex = (tempIndex + 1) % k;
        }
    }

方法二:

在第一種方法中,我們需要不停變換之前的臨時陣列tempArray中的元素,好的,我不想變。

我要考慮另外的思路。

還是上面的例子nums=[1, 2, 3, 4, 5, 6, 7],k=3

初始狀態:1 2 3 4 5 6 7

最終狀態:5 6 7 1 2 3 4

是不是發現了些什麼?

最後的三個元素移動到了前面,前面的元素移動到了後面

像極了將前面的元素刪除之後再插入到後面(在順序表中)【但是我並沒有這樣寫】

程式碼如下:

    public void rotate3(int[] nums, int k) {
        k = k % nums.length;
        if (k == 0)
            return ;
        int[] temp = new int[k];
        int index = 0;
        for (int i = nums.length - k; i < nums.length ; i ++)
            temp[index ++] = nums[i];
        //end store elements
        for (int i = nums.length - k - 1 ; i >= 0 ; i --)
            nums[i+ k] = nums[i];
        for (int i = 0 ; i < k ; i ++)
            nums[i] = temp[i];
    }

方法三:

emm,為什麼要利用一個數組儲存?不能用一個int的量嗎?

可以。

仍然是上面的例子:nums=[1, 2, 3, 4, 5, 6, 7],k=3

我們進行如下的變換:

5(1) 6(2) 7(3) 1(4) 2(5) 3(6) 4(7)

大變換是從nums[0] to nums[3] to nums[6] to nums[2] to nums[5] to nums[1] to nums[4] to nums[0](end)

但是這並不絕對,因為有可能出現nums=[1, 2, 3, 4, 5, 6],k=2的情況,如果還是僅僅從0開始,就會發生如下情況

nums[0] to nums[2] to nums[4] to nums[0](end)

無法完成一次整體的迴圈

針對這種情況,就要依次從0-k-1作為起點進行k次大的變換

程式碼如下:

    public void rotate2(int[] nums, int k) {
        k = k % nums.length;
        if (k == 0)
            return ;
        BitSet bitSet = new BitSet(nums.length);
        int prev;
        int next;
        int nextIndex = 0;
        for (int i = 0 ; i < k ; i ++) {
            next = nums[i];  //每一次開始起始的值都要發生變化
            for (int index = i ; !bitSet.get(index) ; index = nextIndex) {
                nextIndex = (index + k) % nums.length;  //下一個位置
                prev = nums[nextIndex];
                nums[nextIndex] = next;
                next = prev;
                bitSet.set(index);  //標記當前位數
            }
        }
    }

bitset用於記錄那些值是被替換過的,下一次進行迴圈的時候就不會重複操作。