代码随想录day35|343整数拆分96不同的二叉搜索树|01笔记

127 阅读2分钟
  • 343整数拆分

  • 第一印象

  • 使得拆分后乘积较大的方法是尽可能等分当前的数,若拆分后下一层数字大于4则可以再一次拆分。但这样是需要迭代判断的方法,代码构建比较繁琐。
  • 讲解观后感

  • 按照动规解题的思想。首先就是确定dp数组的含义,其中dp[i]一定是代表当前的最大乘积(即题目答案)。
  • 然后是dp的推导公式,dp[i]的获取一个是j * (i - j) 直接相乘。一个是j * dp[i - j],相当于是拆分(i - j)。所以递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
  • 初始化dp[2] = 1
  • dp[i] 是依靠 dp[i - j]的状态,所以遍历i一定是从前向后遍历
  • 解题代码

  •     func integerBreak(n int) int {
            /**
            动态五部曲
            1.确定dp下标及其含义
            2.确定递推公式
            3.确定dp初始化
            4.确定遍历顺序
            5.打印dp
            **/
            dp := make([]int, n+1)
            dp[1] = 1
            dp[2] = 1
            for i := 3; i < n+1; i++ {
                for j := 1; j < i-1; j++ {
        // i可以差分为i-j和j。由于需要最大值,故需要通过j遍历所有存在的值,取其中最大的值作为当前i的最大值,在求最大值的时候,一个是j与i-j相乘,一个是j与dp[i-j].
                    dp[i] = max(dp[i], max(j*(i-j), j*dp[i-j]))
                }
            }
            return dp[n]
        }
        func max(a, b int) int{
            if a > b {
                return a
            }
            return b
        }
    
  • 贪心C++
  • 数学原理需要自己推导
  •     class Solution {
        public:
            int integerBreak(int n) {
                if (n == 2) return 1;
                if (n == 3) return 2;
                if (n == 4) return 4;
                int result = 1;
                while (n > 4) {
                    result *= 3;
                    n -= 3;
                }
                result *= n;
                return result;
            }
        };
    
  • 不同的二叉搜索树

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 确定dp[i]代表n=1时有多少不同的二叉搜索树。
  • 因为是二叉搜索树,所以确定根节点后,可以明确的知道左右子树是哪些数字,并且左右子树的种类相乘就是这个根情况的种类。所以我们只要遍历不同的根节点的情况进行相加即可。
  • 使用j:=1;j<=i;j++进行遍历即可,得到
  •     for j:=1;j<=i;j++ {
                    dp[i] += dp[j-1] * dp[i-j] 
                }
    
  • 易得dp[1], dp[2] = 1, 2,以及当没有数字时可视为一种情况,所以dp[0] = 1
  • 从前向后遍历即可。
  • 讲解观后感

  • 自己一次手撸成功的第一个动规题目,方法和卡尔的思路几乎一摸一样,只不过没有其简洁,原因是没有尽量使递推公式覆盖。但总体差距很小。
  • 解题代码

  •     func numTrees(n int)int{
        	dp := make([]int, n+1)
        	dp[0] = 1
        	for i := 1; i <= n; i++ {
        		for j := 1; j <= i; j++ {
        			dp[i] += dp[j-1] * dp[i-j]
        		}
        	}
        	return dp[n]
        }
    
  • 自己的代码(逻辑一样,只不过多讨论了初始值)
  •     func numTrees(n int) int {
            if n<3 {
                return n
            }
            dp := make([]int, n + 1)
            dp[0] = 1
            dp[1] = 1
            dp[2] = 2
            for i:=3;i<=n;i++ {
                for j:=1;j<=i;j++ {
                    dp[i] += dp[j-1] * dp[i-j] 
                }
            }
            return dp[n]
        }
    
  • 本题解题成功的主要原因是动规的五步方法论确实很方便解题,只要再辅助一些手写推导和对数据结构的理解,就有很大机会自己做出来。