代码随想录算法训练营第四十天|● 343. 整数拆分 ● 96.不同的二叉搜索树

整数拆分 

题目链接:343. 整数拆分 - 力扣(LeetCode)

思路:第一步想的是用递归做,

    int digui(int n){
        if(n==1)return n;
        return max((n/2)*(n-n/2),digui(n/2)*digui(n-n/2));
    }

可惜的是题目并没有规定一定要分成两份,因此这个思路是不对的,但已经初窥门径。正确做法还是用dp,dp[i]的含义是对i进行拆分,所能得到的最大乘积。

 curMax = max(curMax, max(j * (i - j), j * dp[i - j]));表示最大值可能更新自一次拆分或多次拆分。
class Solution {
public:
    int integerBreak(int n) {
                vector <int> dp(n + 1);
        for (int i = 2; i <= n; i++) {
            int curMax = 0;
            for (int j = 1; j < i; j++) {
                curMax = max(curMax, max(j * (i - j), j * dp[i - j]));
            }
            dp[i] = curMax;
        }
        return dp[n];
    }
};

容易看出本题可以采用数学优化,这里引入两个推论,尤其是第二个最为重要:当拆分个数固定时,每个拆分部分大小接近时拆分乘积最大;数字尽可能以3为因子等分时乘积最大。

证明见:https://leetcode.cn/problems/integer-break/solutions/29098/343-zheng-shu-chai-fen-tan-xin-by-jyd

不同的二叉搜索树 

题目链接:96. 不同的二叉搜索树 - 力扣(LeetCode)

思路:从样例里可以看出,如果节点数量是确定的,那么他可以构成的二叉搜索树数量也是固定的,那么我们就能据此构建dp数组。

        for(int i=2;i<=n;i++){
            for(int j=0;j<i;j++){
                dp[i]+=dp[j]+dp[i-j-1];
            }
        }

但是还是有缺陷,因为当2*j==i-1时会导致多算了一种可能。

错错错,这种算法是错误的,正确计算dp[i]应该是dp[j]*dp[i-j-1],而且不需要将2*j==i-1作为特殊情况单独列出。

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n+1);
        dp[0]=1;
        dp[1]=1;
        for(int i=2;i<=n;i++){
            for(int j=0;j<i;j++){
                dp[i]+=dp[j]*dp[i-j-1];
            }
        }
        return dp[n];
    }
};

 

posted @ 2024-03-08 16:16  SandaiYoung  阅读(3)  评论(0编辑  收藏  举报