1. 程式人生 > 其它 >上岸演算法 I LeetCode Weekly Contest 224解題報告

上岸演算法 I LeetCode Weekly Contest 224解題報告

技術標籤:求職

No.1 可以形成最大正方形的矩形數目

解題思路

維護最大正方形的邊長並計數即可。

程式碼展示

class Solution {
    public int countGoodRectangles(int[][] rectangles) {
        int maxLen = 0, count = 0;
        for (int[] rec : rectangles) {
            int len = Math.min(rec[0], rec[1]);
            if (len > maxLen) {
                maxLen =
len; count = 0; } if (len == maxLen) { count++; } } return count; } }

No.2 同積元組

解題思路

用 Map 記錄每一種乘積的因數列表。

程式碼展示

class Solution {
    public int tupleSameProduct(int[] nums) {
        Arrays.sort(nums);
        // map[i] 表示乘積為 i 的較小的因數的列表
// 比如 a * b == i 則 map[i].add(min(a, b)) Map<Integer, List<Integer>> map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { for (int j = i + 1; j < nums.length; j++) { int a = nums[i], b = nums[j]; int p =
a * b; if (!map.containsKey(p)) { map.put(p, new ArrayList<>()); } map.get(p).add(a); // a < b } } // 有 len 對乘積為 i // 它們能構成 4 * len * (len - 1) 個元組 int count = 0; for (var entry : map.entrySet()) { int len = entry.getValue().size(); count += 4 * len * (len - 1); } return count; } }

No.3 重新排列後的最大子矩陣

解題思路

列舉最大子矩陣的起始行,然後排序、統計即可。

程式碼展示

class Solution {
    public int largestSubmatrix(int[][] matrix) {
        Column[] cols = new Column[matrix[0].length];
        for (int i = 0; i < matrix[0].length; i++) {
            int[] col = new int[matrix.length];
            for (int j = 0; j < matrix.length; j++) {
                col[j] = matrix[j][i];
            }
            cols[i] = new Column(col);
        }
        int res = 0;
        // 列舉最大子矩陣的起始行 i, 然後排序
        for (int i = 0; i < matrix.length; i++) {
            final int idx = i;
            Arrays.sort(cols, (a, b) -> b.cont1[idx] - a.cont1[idx]);
            if (res < cols[0].cont1[idx] * cols.length) { // 一個優化點
                res = Math.max(res, count(cols, idx));
            }
        }
        return res;
    }

    // 統計當前局面下的最大子矩陣
    private int count(Column[] cols, int startRow) {
        int res = 0;
        for (int endRow = startRow, endCol = cols.length - 1; endRow < cols[0].raw.length; endRow++) {
            while (endCol >= 0 && cols[endCol].raw[endRow] == 0) {
                endCol--;
            }
            res = Math.max(res, (endRow - startRow + 1) * (endCol + 1));
        }
        return res;
    }

    // Column 類表示一列
    // raw 表示這一列的原始值
    // cont1[i] 表示 raw[i] 後有多少個連續的 1
    class Column {
        int[] raw;
        int[] cont1;

        Column(int[] col) {
            raw = col;
            cont1 = new int[col.length];
            cont1[col.length - 1] = col[col.length - 1];
            for (int i = col.length - 2; i >= 0; i--) {
                cont1[i] = col[i];
                if (col[i] == 1) {
                    cont1[i] += cont1[i + 1];
                }
            }
        }
    }
}

No.4 貓和老鼠II

解題思路

動態規劃(記憶化搜尋)

雖然程式碼量比較大,但是邏輯並不複雜。本質上仍然是列舉貓和老鼠的下一步怎麼走,老鼠想要贏就要保證它走下一步之後,貓無論怎麼走都贏不了。然後使用記憶化以提速。

程式碼展示

class Solution {
    int n, m;
    char[][] grid;
    int[][][][][] catMemo;   // 記憶化
    int[][][][][] mouseMemo; // 記憶化
    int catJump, mouseJump;

    final int[][] dirs = new int[][] { { -1, 0 }, { 1, 0 }, { 0, 1 }, { 0, -1 } };
    final int MaxRound = 100; // 8x8 的地圖遠不需要 1000 步

    public boolean valid(int i, int j) {
        return i >= 0 && i < n && j >= 0 && j < m && grid[i][j] != '#';
    }

    // 已經走了 r 步,老鼠在 (mx, my) 貓在 (cx, cy)
    // 貓是否必勝
    public int cat(int r, int mx, int my, int cx, int cy) {
        if (catMemo[r][mx][my][cx][cy] == -1) {
            if (mx == cx && my == cy) {
                return catMemo[r][mx][my][cx][cy] = 1;
            }
            if (grid[mx][my] == 'F') {
                return catMemo[r][mx][my][cx][cy] = 0;
            }
            if (grid[cx][cy] == 'F') {
                return catMemo[r][mx][my][cx][cy] = 1;
            }
            for (int[] d : dirs) {
                for (int jump = 0; jump <= catJump; jump++) {
                    int x = cx + d[0] * jump;
                    int y = cy + d[1] * jump;
                    if (!valid(x, y)) {
                        break;
                    }
                    if (mouse(r + 1, mx, my, x, y) == 0) {
                        return catMemo[r][mx][my][cx][cy] = 1;
                    }
                }
            }
            catMemo[r][mx][my][cx][cy] = 0;
        }
        return catMemo[r][mx][my][cx][cy];
    }

    // 已經走了 r 步,老鼠在 (mx, my) 貓在 (cx, cy)
    // 老鼠是否必勝
    public int mouse(int r, int mx, int my, int cx, int cy) {
        if (r >= MaxRound) {
            return 0;
        }
        if (mouseMemo[r][mx][my][cx][cy] == -1) {
            if (mx == cx && my == cy) {
                return mouseMemo[r][mx][my][cx][cy] = 0;
            }
            if (grid[mx][my] == 'F') {
                return mouseMemo[r][mx][my][cx][cy] = 1;
            }
            if (grid[cx][cy] == 'F') {
                return mouseMemo[r][mx][my][cx][cy] = 0;
            }
            for (int[] d : dirs) {
                for (int jump = 0; jump <= mouseJump; jump++) {
                    int x = mx + d[0] * jump;
                    int y = my + d[1] * jump;
                    if (!valid(x, y)) {
                        break;
                    }
                    if (cat(r, x, y, cx, cy) == 0) {
                        return mouseMemo[r][mx][my][cx][cy] = 1;
                    }
                }
            }
            mouseMemo[r][mx][my][cx][cy] = 0;
        }
        return mouseMemo[r][mx][my][cx][cy];
    }

    public boolean canMouseWin(String[] grid, int catJump, int mouseJump) {
        n = grid.length;
        m = grid[0].length();
        this.grid = new char[n][m];
        int mx = 0, my = 0, cx = 0, cy = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                this.grid[i][j] = grid[i].charAt(j);
                if (this.grid[i][j] == 'C') {
                    cx = i;
                    cy = j;
                }
                if (this.grid[i][j] == 'M') {
                    mx = i;
                    my = j;
                }
            }
        }
        this.catJump = catJump;
        this.mouseJump = mouseJump;
        catMemo = new int[MaxRound][n][m][n][m];
        mouseMemo = new int[MaxRound][n][m][n][m];

        // 初值 -1 表示未計算過
        for (int r = 0; r < MaxRound; r++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    for (int t = 0; t < n; t++) {
                        for (int k = 0; k < m; k++) {
                            catMemo[r][i][j][t][k] = -1;
                            mouseMemo[r][i][j][t][k] = -1;
                        }
                    }
                }
            }
        }
        return mouse(0, mx, my, cx, cy) == 1;
    }
}