1. 程式人生 > 其它 >旋轉陣列(陣列整體右移k位)

旋轉陣列(陣列整體右移k位)

給定一個數組,將陣列中的元素向右移動k個位置,其中k是非負數。
進階:
儘可能想出更多的解決方案,至少有三種不同的方法可以解決這個問題。
你可以使用空間複雜度為O(1) 的原地演算法解決這個問題嗎?
作者:力扣 (LeetCode)
連結:https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/x2skh7/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

一開始想到了構建一個新陣列作為結果,然後每個元素直接按(當前位置 + k)% length 得到右移之後的新位置放到新陣列內作為結果返回。
不過這個方法顯然不能原地工作Orz。
於是又想到可以只用一個臨時變數儲存隊尾元素,然後每個元素右移一位,最後臨時變數放置到對頭,這樣進行k輪。結果這種方法還超時了。。。

/**
     * 向右移動元素,每次移動一位,移動k次
     * 從後向前開始移動,所以暫存隊尾元素,一輪移動完畢後,暫存元素放至隊首
     * @param nums
     * @param k
     */
    public static void rotate(int[] nums, int k){
        int len = nums.length;
        if(len <= 1){
            return;
        }
        while(k > 0){
            int temp = nums[len - 1];//暫存最後一位元素
            for(int i = len - 2; i >= 0; i--){ //從倒數第二位元素開始,依次右移
                nums[i + 1] = nums[i];
            }
            nums[0] = temp;
            k--;
        }
    }

然後看一下題解,竟然翻轉三次陣列就可以辦到!

/**
     * 反轉三次
     * 1.整體反轉1次
     * 2.前k個元素反轉依次
     * 3.其餘元素反轉一次
     * 上述步驟相當於所有元素右移k位
     * @param nums
     * @param k
     */
    public static void rotate(int[] nums, int k){
        int len = nums.length;
        if(len <= 1){
            return;
        }
        k %= len;
        reverse(nums,0, nums.length - 1);
        reverse(nums, 0, k - 1); //前k個元素對應的下標 個數轉下標要-1
        reverse(nums, k, nums.length - 1);
    }

    /**
     * 反轉陣列[begin, end]範圍內的元素
     * @param array
     * @param begin
     * @param end
     */
    public static void reverse(int[] array, int begin, int end){
        while(begin < end){
            int temp = array[end];
            array[end--] = array[begin];
            array[begin++] = temp;
        }
    }

這個方法真的太妙了,那若是陣列左移k位怎麼辦呢?只需要旋轉後k個元素和其餘元素就可以,程式碼如下

/**
     * 1.陣列整體反轉一遍
     * 2.第二次反轉後k個元素
     * 3.第三次反轉剩餘元素
     * @param nums
     * @param k
     */
    public static void rotate2(int[] nums, int k){
        int len = nums.length;
        if(len <= 1){
            return;
        }
        k %= len;
        int d = len - k; //此時d之後有k個元素,故d為分界線
        reverse(nums,0, len - 1);
        reverse(nums, 0, d - 1); //前k個元素對應的下標 個數轉下標要-1
        reverse(nums, d, len - 1);
    }