旋轉陣列(陣列整體右移k位)
阿新 • • 發佈:2021-10-09
給定一個數組,將陣列中的元素向右移動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);
}