[LeetCode] 189. 旋轉數組

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--;
        }  
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章