记忆化搜索

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));
    }
}
posted @ 2024-05-25 10:33  菠萝包与冰美式  阅读(11)  评论(0编辑  收藏  举报