代码随想录第41天| 96.不同的二叉搜索树 动态规划:01背包理论基础

96.不同的二叉搜索树 

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

输入:n = 3
输出:5

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 19

 

dp[3] , 就是元素1为头节点的搜索树的数量+元素2为头节点的搜索树的数量+元素3为头节点的·搜索树的数量;

元素1为头节点的搜索树的数量=右子树有2个元素的搜索树数量 * 左子树有0个元素的搜索树数量;

元素2为头节点的搜索树的数量=左子树有1个元素的搜索树数量 * 右子树有1个元素的搜索树数量;

元素3为头节点的搜索树的数量=右子树有2个元素的搜索树数量 * 左子树有0个元素的搜索树数量;

有2个元素的搜索树数量就是dp[2];

有1个元素的搜索树数量就是dp[1];

有0个元素的搜索树数量就是dp[0];

所以dp[3]=dp[2]*dp[0] + dp[1] * dp[1] +  dp[0] * dp[2]

动规五部曲

1、确定dp数组以及下标的含义:1到i为节点的组成的二叉搜索树的个数为dp[i];

2、确定递推公式:dp[i] += dp[j - 1] * dp[i - j]; ,j-1 为j为头结点左子树节点数量,i-j 为以j为头结点右子树节点数量

3、dp数组如何初始化:dp[0]=1;

4、确定遍历顺序:从递推公式可以看出,节点数为i的状态是依靠i之前节点数的状态,所以是从前往后遍历;

5、举例推导dp数组:n为5的时候dp数组的状态:

for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                //对于第i个节点,需要考虑1作为根节点直到i作为根节点的情况,所以需要累加
                //一共i个节点,对于根节点j时,左子树的节点个数为j-1,右子树的节点个数为i-j
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }

综合代码:

// 定义一个Solution类
class Solution {
    // 定义一个函数numTrees,参数为整数n,目的是计算n个节点的不同结构的二叉搜索树数量
    public int numTrees(int n) {
        // 初始化一个大小为n+1的整型数组dp,用于保存不同节点数量对应的二叉搜索树数量
        int[] dp = new int[n + 1];
        // 初始化0个节点和1个节点的情况,均为1,因为空树和只有一个节点的树都只有一种情况
        dp[0] = 1;
        dp[1] = 1;
        // 循环遍历从2到n的所有节点数量
        for (int i = 2; i <= n; i++) {
            // 再次循环遍历每个节点数量对应的左子树和右子树节点数量的组合
            for (int j = 1; j <= i; j++) {
                // 对于第i个节点,需要考虑以1到i作为根节点的情况,所以需要累加
                // 当根节点为j时,左子树的节点个数为j-1,右子树的节点个数为i-j
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        // 返回n个节点的不同结构的二叉搜索树数量
        return dp[n];
    }
}

动态规划:01背包理论基础

46. 携带研究材料(第六期模拟笔试) (kamacoder.com)

代码随想录 (programmercarl.com)

带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili

题目描述

小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。他需要带一些研究材料,但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实验样本等等,它们各自占据不同的空间,并且具有不同的价值。 

小明的行李空间为 N,问小明应该如何抉择,才能携带最大价值的研究材料,每种研究材料只能选择一次,并且只有选与不选两种选择,不能进行切割。

输入描述

第一行包含两个正整数,第一个整数 M 代表研究材料的种类,第二个正整数 N,代表小明的行李空间。

第二行包含 M 个正整数,代表每种研究材料的所占空间。 

第三行包含 M 个正整数,代表每种研究材料的价值。

输出描述

输出一个整数,代表小明能够携带的研究材料的最大价值。

输入示例
6 1
2 2 3 1 5 2
2 3 1 5 4 3
输出示例
5
提示信息

小明能够携带 6 种研究材料,但是行李空间只有 1,而占用空间为 1 的研究材料价值为 5,所以最终答案输出 5。 

数据范围:
1 <= N <= 5000
1 <= M <= 5000
研究材料占用空间和价值都小于等于 1000

 动规五部曲

1、确定dp数组以及下标的含义:dp[i][j] 表示从下标为[o-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少;

2、确定递推公式:不放物品i:dp[i-1][j] ;放物品i : 由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值;

所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

3、dp数组的初始化;

4、确定遍历顺序’

5、举例推导dp数组;

综合代码:

public class BagProblem {
    public static void main(String[] args) {
        int[] weight = {1,3,4};
        int[] value = {15,20,30};
        int bagSize = 4;
        testWeightBagProblem(weight,value,bagSize);
    }

    /**
     * 动态规划获得结果
     * @param weight  物品的重量
     * @param value   物品的价值
     * @param bagSize 背包的容量
     */
    public static void testWeightBagProblem(int[] weight, int[] value, int bagSize){

        // 创建dp数组
        int goods = weight.length;  // 获取物品的数量
        int[][] dp = new int[goods][bagSize + 1];

        // 初始化dp数组
        // 创建数组后,其中默认的值就是0
        for (int j = weight[0]; j <= bagSize; j++) {
            dp[0][j] = value[0];
        }

        // 填充dp数组
        for (int i = 1; i < weight.length; i++) {
            for (int j = 1; j <= bagSize; j++) {
                if (j < weight[i]) {
                    /**
                     * 当前背包的容量都没有当前物品i大的时候,是不放物品i的
                     * 那么前i-1个物品能放下的最大价值就是当前情况的最大价值
                     */
                    dp[i][j] = dp[i-1][j];
                } else {
                    /**
                     * 当前背包的容量可以放下物品i
                     * 那么此时分两种情况:
                     *    1、不放物品i
                     *    2、放物品i
                     * 比较这两种情况下,哪种背包中物品的最大价值最大
                     */
                    dp[i][j] = Math.max(dp[i-1][j] , dp[i-1][j-weight[i]] + value[i]);
                }
            }
        }

        // 打印dp数组
        for (int i = 0; i < goods; i++) {
            for (int j = 0; j <= bagSize; j++) {
                System.out.print(dp[i][j] + "\t");
            }
            System.out.println("\n");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值