【LeetCode-陣列】旋轉陣列
阿新 • • 發佈:2020-07-13
題目描述
給定一個數組,將陣列中的元素向右移動 k 個位置,其中 k 是非負數。
示例:
輸入: [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]
輸入: [-1,-100,3,99] 和 k = 2
輸出: [3,99,-1,-100]
解釋:
向右旋轉 1 步: [99,-1,-100,3]
向右旋轉 2 步: [3,99,-1,-100]
說明:
儘可能想出更多的解決方案,至少有三種不同的方法可以解決這個問題。
要求使用空間複雜度為 O(1) 的 原地 演算法。
題目連結: https://leetcode-cn.com/problems/rotate-array/
思路1
每次移動一個元素,陣列中的元素都移動了一次算一遍,移動 k 遍。在移動的時候,假設要把 nums[i] 移動到 nums[j],則要把 nums[j] 在被覆蓋之前儲存起來。
程式碼如下:
class Solution { public: void rotate(vector<int>& nums, int k) { if(k==0 || nums.empty() || nums.size()==1) return; int n = nums.size(); for(int i=0; i<k; i++){ int pre = nums[0]; int cur = 0; for(int j=0; j<n; j++){ cur = nums[(j+1)%n]; nums[(j+1)%n] = pre; pre = cur; } } } }; // 超時
該方法超時。
- 時間複雜度:O(nk)
- 空間複雜度:O(1)
思路2
使用另一個數組儲存旋轉後的結果,然後再用旋轉後的結果覆蓋原陣列。
class Solution { public: void rotate(vector<int>& nums, int k) { if(k==0 || nums.empty() || nums.size()==1) return; int n = nums.size(); vector<int> a(n, 0); for(int i=0; i<n; i++){ a[(i+k)%n] = nums[i]; } for(int i=0; i<n; i++) nums[i] = a[i]; } };
- 時間複雜度:O(n)
- 空間複雜度:O(n)
思路3
我們發現當我們旋轉陣列 k 次, k % n 個尾部元素會被移動到頭部,剩下的元素會被向後移動。所以可以使用反轉:
- 對整個陣列進行反轉,範圍為 [0, n);
- 對前 k 個數字進行反轉,範圍為 [0, k-1);
- 對後 n-k 個數字進行反轉,範圍為 [k, n);
例如:
假設 n=7 且 k=3 。
原始陣列 : 1 2 3 4 5 6 7
反轉所有數字後 : 7 6 5 4 3 2 1
反轉前 k 個數字後 : 5 6 7 4 3 2 1
反轉後 n-k 個數字後 : 5 6 7 1 2 3 4 --> 結果
程式碼如下:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if(k==0 || nums.empty() || nums.size()==1) return;
int n = nums.size();
k = k % n; // 別忘了這一步,因為 k 可能比 n 大
reverse(nums, 0, n-1);
reverse(nums, 0, k-1);
reverse(nums, k, n-1);
}
void reverse(vector<int>& nums, int left, int right){
while(left<right){
swap(nums[left], nums[right]);
left++;
right--;
}
}
};
- 時間複雜度:O(n)
- 空間複雜度:O(1)
參考
https://leetcode-cn.com/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode/