leetcode 189. 旋轉數組

189. 旋轉數組

難度:簡單java

題庫地址:leetcode-cn.com/problems/ro…算法

1. 題目描述

給定一個數組,將數組中的元素向右移動 k 個位置,其中 k 是非負數。數組

示例 1:bash

輸入: [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:spa

輸入: [-1,-100,3,99] 和 k = 2
輸出: [3,99,-1,-100]
解釋: 
向右旋轉 1 步: [99,-1,-100,3]
向右旋轉 2 步: [3,99,-1,-100]
複製代碼

說明:.net

  • 儘量想出更多的解決方案,至少有三種不一樣的方法能夠解決這個問題。
  • 要求使用空間複雜度爲 O(1) 的原地算法。

2. 解題思路

英文版的有答案:leetcode.com/problems/ro…3d

這裏記錄一下第4種方法的理解:Approach #4 Using Reverse [Accepted]code

假設對長度爲 n 的數組,進行 k 次旋轉。leetcode

首先要找到最終有效的次數,由於旋轉的循環的,當對數組進行 n 次旋轉時,至關於沒有對數組進行操做,同時該方法必須先找到最終有效次數,不然無法對數組進行鏡像操做。get

爲何在不一樣位置採用三次鏡像操做就能實現數組的 k 次旋轉,連同答案和本身的理解整理爲以下:

  1. 先計算 k 的有效次數,由於旋轉是循環進行的,像自行車鏈條同樣,當元素旋轉一整圈即:k = n 時,全部元素回到了原來的位置,因此 k 次旋轉的有效次數爲 k \% n

  2. 咱們將數組以 n 爲邊界拆分紅兩部分看待,前 n-k 個元素部分:S_1 = \{t_1,t_2,...,t_{n-k}\} 和 後 n 個元素部分 S_2 = \{t_{n-k+1},t_{n-k+2},...,t_n\}爲何以 k 爲分界點呢?由於對數組進行 k 次旋轉後,S_1S_2 將互換位置。 如數組:\{1,2,3,4,5,6\},長度 n = 6,進行 k=2 次旋轉,對應 S_1 = \{1, 2, 3, 4\}S_2 = \{5,6\},旋轉結束後獲得數組: S_2 = \{5, 6\}S_1 = \{1, 2, 3, 4\}

  3. 爲了實現將 S_1S_2 位置互換,這裏採用將整個數組鏡像的策略。 原元素:\{1,2,3,4,5,6\} 鏡像後:\{6, 5, 4, 3, 2, 1\}

  4. 對數組進行鏡像操做後,雖然 S_1S_2 位置互換,可是其內部元素也被鏡像了,爲了將 S_1S_2 內部元素的順序恢復,對 S_1S_2 再分別進行一次鏡像。

    舉例以下原數組:\{1,2,3,4,5,6\} 鏡像前: S_1 = \{1, 2, 3, 4\}S_2 = \{5,6\} 鏡像後:S_2 = \{6,5\}S_1 = \{4, 3, 2, 1\}S_1S_2 分別進行一次鏡像後獲得的最終結果:S_2 = \{5, 6\}S_1 = \{1, 2, 3, 4\} 最終答案:\{5, 6, 1, 2, 3, 4\}

    算法思想再精簡一點以下:

    1. 對數組以 k 劃分紅兩部分,分爲前 n-k 個元素部分,和後 k 個部分,這樣劃分的目的是旋轉 k 次後這兩部分正好位置互換。
    2. 爲了實現這種位置互換須要將數組鏡像
    3. 鏡像雖然將兩部分數據總體的位置轉換了過來,可是兩部分數組內部數據順序錯誤,須要對兩部分數組分別鏡像

Java實現:

class Solution {
    public void rotate(int[] nums, int k) {
        if (nums == null || nums.length < 2) {
            return;
        }
        // 計算有效旋轉次數
        k %= nums.length;
        // 對整個數組鏡像,使 S2 和 S1 位置互換
        reverse(nums, 0, nums.length - 1);
        // 對 S2 鏡像處理,使其內部元素順序恢復
        reverse(nums, 0, k - 1);
        // 對 S1 鏡像處理,使其內部元素順序恢復
        reverse(nums, k, nums.length - 1);
    }

    private void reverse(int[] nums, int start, int end) {
        while (start < end) {
            int temp = nums[end];
            nums[end] = nums[start];
            nums[start] = temp;
            start++;
            end--;
        }
    }
}
複製代碼
相關文章
相關標籤/搜索