代码随想录训练营第41天|343.整数拆分、96.不同的二叉搜索树

343.整数拆分、96.不同的二叉搜索树

343.整数拆分

贪心

对于贪心的解法,我们先计算几个特例,
假如n == 1,显然结果是1;
假如n == 2,拆分为1+1,结果也是1;
假如n == 3拆分为1+2,结果是2;
假如n == 4,拆分为2+2,结果是4;
当n>4时,我们将其拆分为尽可能多的3,如果剩下的数拆分为3后剩余为1,则不用拆分了,因为4>3*1。

代码
class Solution {
public:
    int integerBreak(int n) {
        if(n==1||n==2) return 1;
        if(n==3) return 2;
        int result =1;
        while(n>4)
        {
            result*=3;
            n-=3;
        }
        result*=n;
        return result;
    }
};

动态规划

同上面,
假如n == 1,我们返回1;
假如n == 2,返回1;
假如n == 3,返回2;

1.确定dp数组,并且确定其含义。
2.确定推导公式。
3.dp数组如何初始化。
4.确定遍历顺序。
5.举例推导bp数组。

1.我们确定dp数组为整数n对应的最大的结果。
2.dp[n] = max(dp[ii]*dp[n-ii]) {ii>=1&&ii 3.因为要让他们相乘,因此,初始化dp[0]=dp[1]=1,dp[2]=2,dp[3]=3;
4.遍历顺序为从前向后遍历。

代码
class Solution {
public:
    int integerBreak(int n) {
        if(n==1||n==2) return 1;
        if(n==3) return 2;
        vector<int>dp(n+1);
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 2;
        dp[3] = 3;
        for(int ii =4;ii<=n;ii++)
        {
            int maxi=1;
            for(int jj =1;jj<ii;jj++)
            {
                maxi = max(maxi,dp[jj]*dp[ii-jj]);
            }
            dp[ii] = maxi;
        }
        return dp[n];
    }
};

96.不同的二叉搜索树

动态规划

对于二叉搜索树(加入节点数为n),如果新加入一个节点,我们可以将其放在根节点处,那么其左右子树可以设置为(0,n),(1,n-1),(2,n-2)……(n-1,1),(n,0)。
假如没有节点,那么子树的种类为f(0)=1,
只有一个节点,子树的种类为f(1)=1,
有两个节点,子树的种类为f(2)=2,
若有三个节点,那么我们固定一个节点为根节点,那么其左子树可能的节点树为0,1,2;对应的右子树的节点数为2,1,0.因此f(3)=f(0)*f(2)+f(1)*f(1)+f(2)*f(1)=5
同理,若节点数为n时,f(n)=f(0)*f(n-1)+f(1)*f(n-2)+…+f(n-2)*f(1)+f(n-1)*f(0)
按此逻辑递推即可。

1.确定dp数组,并且确定其含义。
2.确定推导公式。
3.dp数组如何初始化。
4.确定遍历顺序。
5.举例推导bp数组。

1.dp数组为节点为n时的二叉树种类数
2.f(n)=f(0)*f(n-1)+f(1)*f(n-2)+…+f(n-2)*f(1)+f(n-1)*f(0)
3.初始化dp[0]=1,dp[1]=1,dp[2]=2
4.从前向后进行遍历即可。

代码
class Solution {
public:
    int numTrees(int n) {
        if(n==0||n==1) return 1;
        if(n==2) return 2;
        vector<int>dp(n+1,0);
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 2;
        for(int ii =3;ii<=n;ii++)
        {
            for(int jj = 0;jj<ii;jj++)
                dp[ii]+=dp[jj]*dp[ii-1-jj];
        }
        return dp[n];
    }
};

卡特兰数

形如递推公式为f(n)=f(0)*f(n-1)+f(1)*f(n-2)+…+f(n-2)*f(1)+f(n-1)*f(0)
前面几项为1,1,2,5之类,被成为卡特兰数,它们有着一个求第n项的公式。
代码随想录训练营第41天|343.整数拆分、96.不同的二叉搜索树_第1张图片
因此,我们可以直接利用公式进行求解即可。
需要注意的是,此处为乘除法,因此可能会导致溢出,所以尽量用长整型。
如果向笔者一样,用一个for循环解决的话,需要注意int类型是否会进行向下取整的情况。

代码
class Solution {
public:
    int numTrees(int n) {
        long double result=1.0;
        for(int ii =n+2;ii<=2*n;ii++)
        {
            result*=ii;
            result/=(ii-n);
        }
        return int(result);
    }
};

你可能感兴趣的:(算法,动态规划,leetcode)