LeetCode:48.旋轉圖像

給定一個 n × n 的二維矩陣表示一個圖像。
將圖像順時針旋轉 90 度。
說明:
你必須在原地旋轉圖像,這意味着你需要直接修改輸入的二維矩陣。請不要使用另一個矩陣來旋轉圖像。

示例 1:
給定 matrix = 
[
    [1,2,3],
    [4,5,6],
    [7,8,9]
],

原地旋轉輸入矩陣,使其變爲:
[
    [7,4,1],
    [8,5,2],
    [9,6,3]
]

示例 2:
給定 matrix =
[
    [ 5, 1, 9,11],
    [ 2, 4, 8,10],
    [13, 3, 6, 7],
    [15,14,12,16]
], 

原地旋轉輸入矩陣,使其變爲:
[
    [15,13, 2, 5],
    [14, 3, 4, 1],
    [12, 6, 8, 9],
    [16, 7,10,11]
]

分析:
題目意思很簡單,很容易理解。如果題目不給限制,那麼很好做,新建一個同樣大小的二維數組,將每一個元素按照新的位置要求存入即可。但題目要求在原地完成,不創建新數組,當然也不能新建其他的存儲元素的數據結構。這樣一下子把題目提高了一大截。
既然是原地旋轉,那我們就需要看一下每一個元素是如何移動的。
我們看示例1中給出的 3 3 的二維數組。
左上角的元素1,旋轉之後再右上角,那麼腳標的變化就是
[0][0] --> [0][2]
其他的元素以此類推的旋轉:
[0][2] --> [2][2]
[2][2] --> [2][0]
[2][0] --> [0][0]
[0][1] --> [1][1]
[1][1] --> [2][1]
[2][1] --> [1][0]
[1][0] --> [0][1]
請在這個過程中找到換位的規律。
再看示例2中的 4
4 的二維數組。
[0][0] --> [0][3]
[0][3] --> [3][3]
[3][3] --> [3][0]
[3][0] --> [0][0]
[0][1] --> [1][3]
[0][2] --> [2][3]
[1][1] --> [1][2]
使用歸納法,我們可以發現規律:

[x][y] --> [y][n - 1 - x]

這樣,我們得到任何一個元素,只需要根據它的兩個腳標就可以得出它要去到哪個位置。
現在要選擇移動的方法,可以使用臨時變量temp來作爲暫存變量,幫助換位置,但這樣的速度較慢。建議使用異或的方法。
a = a ^ b
b = a ^ b
a = a ^ b
這種方法效率高,速度快。
好的,找到目的地的腳標後,準備好移動元素了。
那麼如何移動?是用雙重for循環,按照0到n-1的順序讓所有元素交換嗎?這樣是不行的。如果按照順序那麼[0][0]將會存放到[0][n-1],那麼[0][n-1]原本的值怎麼辦?當按照順序遍歷到[0][n-1]時,去哪裏得到其原本的值。所以按照順序遍歷移位是不行的。
那麼怎麼辦?仔細觀察可以發現,一個矩陣裏面,旋轉會讓4個元素互相到達對方的位置,可以把對應的4個元素歸爲一組。比如:
[0][0] --> [0][3]
[0][3] --> [3][3]
[3][3] --> [3][0]
[3][0] --> [0][0]
這是矩陣四個角的4個元素歸爲了一組,旋轉圖像就是它們的位置互換。我們可以利用這個規律,讓矩陣一次把一組4個元素的位置全部換完,然後再進行下一組4個元素。
我們可以使用兩兩換位的方法完成,讓一個元素連續換位置3次,就可以讓4個元素都到達各自需要的地方。按照這個思路,那麼不能按照順時針方向的元素去交換,因爲讓一個元素按照順時針方向交換位置3次,那麼所有的元素都想逆時針方向旋轉了90度,這不符合題意。只能按照逆時針方向交換位置3次。
那麼順時針方向腳標變化的規律是:

[x][y] --> [y][n - 1 - x]

可以得到逆時針方向腳標變化的規律是:

[x][y] --> [n - 1 - y][x]

那麼可以得到變化的代碼

 for (int j = 0; j < 3; j++) {
                x2 = n - 1 - y1;
                y2 = x1;

                matrix[x1][y1] = matrix[x1][y1] ^ matrix[x2][y2];
                matrix[x2][y2] = matrix[x1][y1] ^ matrix[x2][y2];
                matrix[x1][y1] = matrix[x1][y1] ^ matrix[x2][y2];

                x1 = x2;
                y1 = y2;
        }

上面的for循環是固定進行3次,每一次兩兩換位置之後,用新位置的腳標繼續進行換位置。這樣一組4個元素就完成了旋轉。
好的,完成上面的代碼,就說明工作完成了一半了。
接下來要考慮的就是,如何找到4個元素爲一組的每一組。
繼續觀察:
3 3 的矩陣,有9個元素,需要旋轉2組元素。
4
4 的矩陣,有16個元素,需要旋轉4組元素。
可以總結規律旋轉的次數:

int count = n * n / 4;

最後,比較困難的部分就是如何定位到矩陣中的每一個組需要旋轉的元素。
3 3 的矩陣,需要旋轉2組元素,需要定位到 [0][0], [0][1]
4
4 的矩陣,需要旋轉4組元素,需要定位到 [0][0], [0][1], [0][2], [1][1]
5 * 5 的矩陣,需要旋轉6組元素,需要定位到 [0][0], [0][1], [0][2], [0][3], [1][1], [1][2]
...
這一步比較困難,好在筆者在思考良久才尋到的法子。過程不解釋了,大家從下面完整的解答代碼中看吧。
以下是java解答:

public void rotate(int[][] matrix) {
    int n = matrix.length;

    if (n <= 1) {
        return;
    }

    //旋轉次數
    int count = n * n / 4;

    int x = 0;
    int y = 0;
    int z = 0;

    int x1, y1, x2, y2;

    for (int i = 0; i < count; i++) {
        if (z >= (n - 1) - 2 * x) {
            x += 1;
            z = 0;
        }
        y = z + x;
        z += 1;

        x1 = x;
        y1 = y;

        for (int j = 0; j < 3; j++) {
            x2 = n - 1 - y1;
            y2 = x1;

            matrix[x1][y1] = matrix[x1][y1] ^ matrix[x2][y2];
            matrix[x2][y2] = matrix[x1][y1] ^ matrix[x2][y2];
            matrix[x1][y1] = matrix[x1][y1] ^ matrix[x2][y2];

            x1 = x2;
            y1 = y2;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章