記憶化搜尋

菠萝包与冰美式發表於2024-05-25

Leetcode 329. 矩陣中的最長遞增路徑

矩陣中的最長遞增路徑

給定一個 m x n 的整數矩陣 matrix,找出其中最長遞增路徑的長度。對於每個單元格,你可以往上、下、左、右四個方向移動。你不能在對角線方向上移動或移動到邊界外。

題解:記憶化搜尋

我們使用記憶化搜尋(Memoization)結合深度優先搜尋(DFS)來解決這個問題。具體步驟如下:

步驟

  1. 狀態定義

    • 定義 ( f[i][j] ) 表示從單元格 ( (i, j) ) 開始的最長遞增路徑的長度。
  2. 狀態轉移方程

    • 對於每個單元格 ( (i, j) ),考慮所有可以前往的單元格 ( (a, b) )。狀態轉移方程為:

      f[i][j] = max(f[i][j], f[a][b] + 1)

      這意味著如果可以從 ( (i, j) ) 移動到 ( (a, b) ),那麼從 ( (i, j) ) 開始的最長路徑至少是從 ( (a, b) ) 開始的最長路徑加一。

  3. 初始化

    • 初始化所有的 ( f[i][j] ) 為 (-1),表示每個單元格開始的最長路徑尚未計算。
  4. 遞迴搜尋

    • 對於每個單元格 ( (i, j) ),使用深度優先搜尋(DFS)計算從該單元格開始的最長遞增路徑,並利用記憶化搜尋儲存和重用之前計算的結果。(其實就是visit陣列)

實現

public class Solution {
    private int[][] matrix;
    private int[][] cache;
    private int n;
    private int m;
    private int[] dx = {-1, 1, 0, 0}; // 方向陣列,表示上下左右
    private int[] dy = {0, 0, 1, -1}; // 方向陣列,表示上下左右

    public int longestIncreasingPath(int[][] matrix) {
        if (matrix == null || matrix.length == 0) return 0;
        this.matrix = matrix;
        this.n = matrix.length;
        this.m = matrix[0].length;
        this.cache = new int[n][m];
        int res = 0;
        // 遍歷每個單元格
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // 找到從每個單元格開始的最長路徑
                res = Math.max(res, dfs(i, j));
            }
        }
        return res;
    }

    private int dfs(int x, int y) {
        // 如果快取中已有結果,直接返回
        if (cache[x][y] != 0) return cache[x][y];
        int max = 1; // 當前單元格的最長路徑長度
        // 訪問四個方向
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            // 檢查新位置是否合法以及是否遞增
            if (nx < 0 || nx >= n || ny < 0 || ny >= m || matrix[nx][ny] <= matrix[x][y]) continue;
            // 計算從新位置開始的路徑長度
            int len = 1 + dfs(nx, ny);
            // 更新最長路徑長度
            max = Math.max(max, len);
        }
        // 快取結果
        cache[x][y] = max;
        return max;
    }
}

huawei2023112903

給定一個整數 ( n ),構造由值為 1 到 ( n ) 的節點組成的二叉搜尋樹,求出高度不超過 ( k ) 的不同二叉搜尋樹的數量(根節點高度為 1)。

輸入描述

  • 兩個整數 ( n ) 和 ( k ),滿足 ( 1 \leq n, k \leq 35 )。

輸出描述

  • 一個整數,表示不同二叉搜尋樹的數量。

示例

輸入:

5 4

輸出:

26

思路

定義 ( cache[i][j] ) 為在有 ( i ) 個節點,並且樹的高度不超過 ( j ) 的情況下,可以構造的二叉查詢樹的數量。

可以使用動態規劃或者記憶化搜尋來實現。

具體步驟如下:

  1. 初始狀態

    • 如果 ( k ) 為 0 且 ( n \neq 0 ),表示樹的高度已經超過了 ( k ),那麼不能再構造出新的樹,返回 0。
    • 如果 ( k ) 為 0 且 ( n ) 也為 0,表示沒有節點且高度為 0,也只能構造出一棵空樹,返回 1。
    • 如果 ( n ) 為 0,表示沒有節點,那麼只能構造出一棵空樹,返回 1。
  2. 遞迴計算

    • 對於每個 ( n ),可以分別列舉給左子樹分配 ( [1:n-1] ) 個節點,右子樹分配 ( [n-1:0] ) 個節點,並將對應的方案累乘,即為當前的方案數,累加當前方案數即為最終答案。
  3. 記憶化搜尋

    • 為了避免重複計算,需要使用記憶化搜尋。定義 dfs(cnt, dep) 函式表示當前有 cnt 個節點,樹的高度為 dep 時,能構造出的二叉查詢樹的數量。
    • 如果之前已經計算過 dfs(cnt, dep),則直接返回快取的結果。
import java.util.Scanner;

public class Main {
    // Define the maximum size for cache
    static final int N = 40;
    // Initialize cache for memoization k<=35
    static int[][] cache = new int[N][N];

    // Depth-first search function for memoization
    static int dfs(int n, int k) {
        // If the result for (n, k) is already calculated, return it directly from cache(memory search)
        if (cache[n][k] != -1) return cache[n][k];
        // Base cases
        if (k == 0 && n == 0) return 1; // If both k and n are 0, return 1 as there's only one empty tree
        if (k == 0 && n != 0) return 0; // If k is 0 but n is not, return 0 as it's impossible to construct a tree
        if (n == 0) return 1; // If n is 0, return 1 as there's only one empty tree
        int res = 0;
        // Recursively calculate the number of BSTs
        for (int i = 1; i <= n; ++i) {
            res += dfs(i - 1, k - 1) * dfs(n - i, k - 1);
        }
        // Cache the result for (n, k)
        return cache[n][k] = res;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // Read input values for n and k
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        // Initialize cache with -1
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                cache[i][j] = -1;
            }
        }
        // Calculate and print the result
        System.out.println(dfs(n, k));
    }
}

相關文章