189. 旋轉數組
難度:Easy
題目描述:
給定一個數組,將數組中的元素向右移動 k 個位置,其中 k 是非負數。
示例 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]
解題思路:
解法一:暴力法
循環移位k次:先記錄最後一位爲pre,依次遍歷nums數組,往後移一位。
時間複雜度O(nk),空間複雜度O(n)。
會超時。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
for (int i = 0; i < k; i++)
{
int pre = nums[nums.size() - 1];
for (int j = 0; j < nums.size(); j++)
{
int temp = nums[j];
nums[j] = pre;
pre = temp;
}
}
}
};
解法二:拷貝法
新建一個新的數組new,將舊數組中的元素i,放到新數組中的(i+k)%N的位置。然後再將新數組中的元素拷貝回去。
時間複雜度O(N),空間複雜度O(N)。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int temp[30000];
int N = nums.size();
for (int i = 0; i < N; i++)
{
temp[(i + k) % N] = nums[i];
}
for (int i = 0; i < N; i++)
{
nums[i] = temp[i];
}
}
};
解法三:環形替換
在解法二的基礎上,不再使用額外的數組,直接依次向後移動,進行替換。
將第i個元素放到i+k位置上,然後將i+k位置上的放到i+k+k上,依次迭代。
當回到原點時,有可能不是所有的點都替換完成了(N%k==0時),因此需要尋找下一個開始的位置。
結束條件:所有的點N都移動一次,因此用一個計數器count記錄。
時間複雜度O(N),空間複雜度O(1)。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
k = k % nums.size(); // 處理 k>N時的情況
int N = nums.size();
int count = 0;
for (int start = 0; count < N; start++) // 注意這裏結束條件是count == N時
{
int cur = start;
int pre = nums[cur];
do
{
int next = (cur + k) % N; // 記錄被替換的結點
int temp = nums[next];
nums[next] = pre; // 更新
cur = next; // 被替換的結點變爲開始
pre = temp;
count++;
} while (start != cur); // 當沒有回到原點時,一直迭代替換
}
}
};
解法四:3次逆置
對前半部分(0, size - k - 1)進行數組逆置;
對後半部分(size - k - 1)進行數組逆置;
對全部(0, size - 1)的數組進行逆置。
時間複雜度O(N),空間複雜度O(1).
class Solution {
public:
void rotate(vector<int>& nums, int k) {
k = k % nums.size();
reverse(nums, 0, nums.size() - k - 1);
reverse(nums, nums.size() - k, nums.size() - 1);
reverse(nums, 0, nums.size() - 1);
}
// 逆置[start, end]區間內的元素
void reverse(vector<int>& nums, int start, int end){
while (start < end)
{
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
};