二維數(shù)組(矩陣)


螺旋矩陣遍歷

給定一個包含 m x n 個元素的矩陣(m 行, n 列),請按照順時針螺旋順序,返回矩陣中的所有元素。

示例 1:
輸入:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
輸出: [1,2,3,6,9,8,7,4,5]
示例 2:

輸入:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
輸出: [1,2,3,4,8,12,11,10,9,5,6,7]

模擬順時針旋轉(zhuǎn)
繪制螺旋軌跡路徑,我們發(fā)現(xiàn)當(dāng)路徑超出界限或者進(jìn)入之前訪問過的單元格時,會順時針旋轉(zhuǎn)方向。

public static List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> ret = new ArrayList<>();

        if (matrix.length == 0) {
            return ret;
        }

        int m = matrix.length;
        int n = matrix[0].length;
        boolean[][] seen = new boolean[m][n];

        int row = 0;
        int col = 0;
        // dRow, dCol代表方向, dInd控制方向轉(zhuǎn)變
        int[] dRow = {0, 1, 0, -1};
        int[] dCol = {1, 0, -1, 0};
        int dInd = 0;

        for (int i = 0; i < m * n; i++) {

            ret.add(matrix[row][col]);
            seen[row][col] = true;

            int potNextRow = row + dRow[dInd];
            int potNextCol = col + dCol[dInd];

            if (potNextRow >= 0 && potNextRow < m && potNextCol >= 0 && potNextCol < n && !seen[potNextRow][potNextCol]) {
                row = potNextRow;
                col = potNextCol;
            } else {
                dInd = (dInd + 1) % 4;
                row += dRow[dInd];
                col += dCol[dInd];
            }
        }

        return ret;
    }

逐層模擬
答案是最外層所有元素按照順時針順序輸出,其次是次外層,以此類推。

 public static List<Integer> spiralOrder2(int[][] matrix) {
        List<Integer> ret = new ArrayList<>();

        if (matrix.length == 0) {
            return ret;
        }

        int m = matrix.length;
        int n = matrix[0].length;

        int r1 = 0;
        int r2 = m - 1;
        int c1 = 0;
        int c2 = n - 1;

        while (r1 <= r2 && c1 <= c2) {
            for (int c = c1; c <= c2; c++) {
                ret.add(matrix[r1][c]);
            }
            for (int r = r1 + 1; r <= r2; r++) {
                ret.add(matrix[r][c2]);
            }
            if(r1 < r2 && c1 < c2){ // 防止重復(fù)
                for (int c = c2 - 1; c >= c1; c--) {
                    ret.add(matrix[r2][c]);
                }
                for (int r = r2 - 1; r >= r1 + 1; r--) {
                    ret.add(matrix[r][c1]);
                }
            }
            r1++;
            c1++;
            r2--;
            c2--;
        }

        return ret;
    }


盛最多水的容器

給你 n 個非負(fù)整數(shù) a1,a2,...,an,每個數(shù)代表坐標(biāo)中的一個點(diǎn) (i, ai) 。在坐標(biāo)內(nèi)畫 n 條垂直線,垂直線 i 的兩個端點(diǎn)分別為 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構(gòu)成的容器可以容納最多的水。

圖中垂直線代表輸入數(shù)組 [1,8,6,2,5,4,8,3,7]。在此情況下,容器能夠容納水(表示為藍(lán)色部分)的最大值為 49。

說明:你不能傾斜容器,且 n 的值至少為 2。
示例:
輸入:[1,8,6,2,5,4,8,3,7]
輸出:49

雙指針
由于容納的水量是由兩個指針指向的數(shù)字中較小值 * 指針之間的距離決定的。所以每次我們移動兩個數(shù)字中數(shù)字較小的那個,才有可能使得容納水量變多。

public static int maxArea(int[] height) {

        int L = 0;
        int R = height.length - 1;

        int maxArea = 0;
        while (L <= R){
            int area = Math.min(height[L], height[R]) * (R - L);
            maxArea = Math.max(maxArea, area);
            if(height[L] < height[R]){
                L++;
            }else {
                R--;
            }
        }

        return maxArea;
    }

螺旋矩陣 II(https://leetcode-cn.com/problems/spiral-matrix-ii/)

給定一個正整數(shù) n,生成一個包含 1 到 n2 所有元素,且元素按順時針順序螺旋排列的正方形矩陣。
示例:
輸入: 3
輸出:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]

模擬旋轉(zhuǎn)法
關(guān)鍵:使用{0, 1, 0, -1},{1, 0, -1, 0},ind % 4的組合模擬方向的旋轉(zhuǎn)

public static int[][] generateMatrix(int n) {

        int[][] res = new int[n][n];

        int[] raw_dir = {0, 1, 0, -1};
        int[] col_dir = {1, 0, -1, 0};
        int dir = 0;

        int num = 1;
        int max = (int) Math.pow(n, 2);
        int i=0;
        int j=0;
        while (num <= max){
            if(i < n && i >= 0 && j < n && j >=0 && res[i][j] == 0){
                res[i][j] = num++;
            }else {
                // 回退到前一步
                i -= raw_dir[dir];
                j -= col_dir[dir];
                // 更改方向
                dir = (dir + 1) % 4;
            }
            i += raw_dir[dir];
            j += col_dir[dir];
        }
        return res;
    }

設(shè)定邊界法
關(guān)鍵:
1)定義當(dāng)前左右上下邊界 l,r,t,b,初始值 num = 1,迭代終止值 tar = n * n;
2)當(dāng) num <= tar 時,始終按照 從左到右、 從上到下、 從右到左 、從下到上 填入順序循環(huán),每次填入后:
執(zhí)行 num += 1:得到下一個需要填入的數(shù)字;
更新邊界:例如從左到右填完后,上邊界 t += 1,相當(dāng)于上邊界向內(nèi)縮 1。

class Solution {
    public int[][] generateMatrix(int n) {
        int l = 0, r = n - 1, t = 0, b = n - 1;
        int[][] mat = new int[n][n];
        int num = 1, tar = n * n;
        while(num <= tar){
            for(int i = l; i <= r; i++) mat[t][i] = num++; // left to right.
            t++;
            for(int i = t; i <= b; i++) mat[i][r] = num++; // top to bottom.
            r--;
            for(int i = r; i >= l; i--) mat[b][i] = num++; // right to left.
            b--;
            for(int i = b; i >= t; i--) mat[i][l] = num++; // bottom to top.
            l++;
        }
        return mat;
    }
}

搜索二維矩陣 II(https://leetcode-cn.com/problems/search-a-2d-matrix-ii/)

編寫一個高效的算法來搜索 m x n 矩陣 matrix 中的一個目標(biāo)值 target。該矩陣具有以下特性:
每行的元素從左到右升序排列。
每列的元素從上到下升序排列。
示例:
現(xiàn)有矩陣 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
給定 target = 5,返回 true。
給定 target = 20,返回 false。

左下角遍歷法
但凡此類的問題,都可以從左下角(或者右上角)開始遍歷。
算法:
首先,我們初始化一個指向矩陣左下角的 (row,col)指針。然后,直到找到目標(biāo)并返回 true(或者指針指向矩陣維度之外的 (row,col) 為止,我們執(zhí)行以下操作:如果當(dāng)前指向的值大于目標(biāo)值,則可以 “向上” 移動一行。 否則,如果當(dāng)前指向的值小于目標(biāo)值,則可以移動一列。不難理解為什么這樣做永遠(yuǎn)不會刪減正確的答案;因?yàn)樾惺菑淖蟮接遗判虻?,所以我們知道?dāng)前值右側(cè)的每個值都較大。 因此,如果當(dāng)前值已經(jīng)大于目標(biāo)值,我們知道它右邊的每個值會比較大。也可以對列進(jìn)行非常類似的論證,因此這種搜索方式將始終在矩陣中找到目標(biāo)(如果存在)。

public static boolean searchMatrix(int[][] matrix, int target) {

        int m = matrix.length;
        if(m == 0){
            return false;
        }
        int n = matrix[0].length;
        if(n == 0){
            return false;
        }

        int r = m-1;
        int c = 0;
        while (r >= 0 && c < n){
            if (target == matrix[r][c]) {
                return true;
            }
            if (target < matrix[r][c]) {
                r--;
            }else {
                c++;
            }
        }

        return false;
    }

旋轉(zhuǎn)圖像


按層旋轉(zhuǎn)
1)先按層劃分,比如示例2,可分為兩層,外圈和內(nèi)圈。
2)每層再按照位置旋轉(zhuǎn),比如示例2,15-5-11-16旋轉(zhuǎn),13-1-10-12旋轉(zhuǎn),2-9-7-14旋轉(zhuǎn)即可。
技巧:每一層先確定四個角的坐標(biāo),然后通過offset就可以比較清晰地得到旋轉(zhuǎn)的四個數(shù)的對應(yīng)坐標(biāo)。

public static void rotate(int[][] matrix) {
        int n = matrix.length;
        if (n <= 1) {
            return;
        }
        for (int level = 0; level <= n / 2 - 1; level++) {
            int start = level;
            int end = n - level - 1;
            // (start, start)   (start, end)
            // (end, start)     (end, end)
            for (int col = start; col < end; col++) {
                int offset = col - start;
                int temp = matrix[start][start + offset];
                matrix[start][start + offset] = matrix[end - offset][start];
                matrix[end - offset][start] = matrix[end][end - offset];
                matrix[end][end - offset] = matrix[start + offset][end];
                matrix[start + offset][end] = temp;
            }
        }
    }

先轉(zhuǎn)置,再翻轉(zhuǎn)每行

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

    // transpose matrix
    for (int i = 0; i < n; i++) {
      for (int j = i; j < n; j++) {
        int tmp = matrix[j][i];
        matrix[j][i] = matrix[i][j];
        matrix[i][j] = tmp;
      }
    }
    // reverse each row
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n / 2; j++) {
        int tmp = matrix[i][j];
        matrix[i][j] = matrix[i][n - j - 1];
        matrix[i][n - j - 1] = tmp;
      }
    }
  }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容