动态规划题目集合——贰

1.零钱兑换

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。

题目链接

题目解析:

1.动态规划首先需要知道问题的最后一步是什么,我们是要求达到总金额x时最少的硬币总数

2.知道最后一步我们就要推导问题的子问题,假设我们有硬币x1,x2,x4,那么在求达到总金额amount的时候的硬币数量,我们可以将最后一步分解为 amount-x1/zmount-x2/amount-x3 +1

3.再将子问题不断分解,继续向前推进就可以得到转移方程,假设当前硬币数量为dp[i],硬币金额有1,3, 5种,那么转移方程为dp[i]=fmin(dp[amount-1],dp[amount-3],dp[amount-5])+1;

在这里插入图片描述

2.完全平方数

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

题目链接

题目解析:
这题认真一看,会发现其实是和上题的思路是一样的
求构成正整数n,需要多少个数的平方和。

1.找到最后一步,分解为子问题
设构成n的数为x1,x2,x3…xn, 并且这些数都会满足条件x<sqrt(n)。
设最后构成n所需要的数字个数为dp[n],那么到达dp[n]的前一步是,dp[n-x1^2] 或者是 dp[n-x22]…dp[n-xn2]

2.将子问题再进行分解,推导出转移方程
至此,就将构成所需要的数字个数分解为了上面的子问题 dp[n-x1^2] 或者是 dp[n-x22]…dp[n-xn2],我们将子问题进行比较,找到所需构成数字,最少的那一个子问题,加上一就是构成n所需要的数字
再将子问题同样进行递推分解,得到转移方程dp[i]=fmin(dp[i-x1],dp[i-x2],…,dp[i-x3])+1;

在这里插入图片描述

3.最大正方形

3.1正常解法

在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。
题目链接
在这里插入图片描述

int maximalSquare(char** matrix, int matrixSize, int* matrixColSize){
    
    int line=*matrixColSize;


    for(int i=0;i<matrixSize;i++)//matrix char 类型,注意陷阱
    {
        for(int j=0;j<line;j++)
        {
            matrix[i][j]-='0';//转换成数字
        }
    }
    for(int i=1;i<matrixSize;i++)//从1开始,是因为上和左边界为右下角的正方形最大边长就是自己
    {
        for(int j=1;j<line;j++)
        {
            if(matrix[i][j]!=0)//自己不能为零
            {
                matrix[i][j]=
                ((matrix[i-1][j]>matrix[i][j-1]?matrix[i][j-1]:matrix[i-1][j])
                >matrix[i-1][j-1]?matrix[i-1][j-1]:
                (matrix[i-1][j]>matrix[i][j-1]?matrix[i][j-1]:matrix[i-1][j]))+1;

            }
        }
    }
   int max=0;
    for(int i=0;i<matrixSize;i++)
    {
        for(int j=0;j<line;j++)
        {
           max= matrix[i][j]>max?matrix[i][j]:max;//找出最大的max
        }
    }
    return max*max;

3.2不破坏原始空间写法

int maximalSquare(char** matrix, int matrixSize, int* matrixColSize){
    
    int line=*matrixColSize;

    int **ret=(int **)malloc(sizeof(int*)*matrixSize);
    
    for(int i=0;i<matrixSize;i++)
    {
        ret[i]=(int*)calloc(line,sizeof(int));
    }
 
    for(int i=0;i<matrixSize;i++)
    {
        for(int j=0;j<line;j++)
        {   
            if(matrix[i][j]!='0')//自己不能为零
            {
                if(i==0||j==0)//在边界上
                ret[i][j]=1;
                else
                ret[i][j]=
                ((ret[i-1][j]>ret[i][j-1]?ret[i][j-1]:ret[i-1][j])
                >ret[i-1][j-1]?ret[i-1][j-1]:
                (ret[i-1][j]>ret[i][j-1]?ret[i][j-1]:ret[i-1][j]))+1;
            }
        }
    }
   int max=0;
    for(int i=0;i<matrixSize;i++)
    {
        for(int j=0;j<line;j++)
        {
           max= ret[i][j]>max?ret[i][j]:max;//找出最大的max
        }
    }

    return max*max;

}

3.3不破坏空间,且降低空间复杂度

由于我们只需要用到上方,和左方的正方形,因此只需要两个一维数组即可

int maximalSquare(char** matrix, int matrixSize, int* matrixColSize){
    
    int line=*matrixColSize;

   int *ret1=(int *)calloc(line,sizeof(int));
   int *ret2=(int *)calloc(line,sizeof(int)); 

   int max=0;//最大值保存变量

 
    for(int i=0;i<matrixSize;i++)//从1开始,是因为上和左边界为右下角的正方形最大边长就是自己
    {
        for(int j=0;j<line;j++)
        {   
            if(matrix[i][j]!='0')//自己不能为零
            {
                if(i%2==0)//为奇
                {
                    if(i==0||j==0)//在边界上
                    ret1[j]=1;
                
                else
                    ret1[j]=((ret1[j-1]>ret2[j-1]?ret2[j-1]:ret1[j-1])>ret2[j]?
                    ret2[j]:(ret1[j-1]>ret2[j-1]?ret2[j-1]:ret1[j-1]))+1;

                    max=fmax(max,ret1[j]);
                }
                else//为偶
                {
                     if(i==0||j==0)//在边界上
                     ret2[j]=1;

                    else
                        ret2[j]=((ret2[j-1]>ret1[j-1]?ret1[j-1]:ret2[j-1])>ret1[j]?
                        ret1[j]:(ret2[j-1]>ret1[j-1]?ret1[j-1]:ret2[j-1]))+1;

                  max=fmax(max,ret2[j]);

                }
            }
            else//matrix为零时
                {
                    if(i%2==0)
                    ret1[j]=0;
                    else
                    ret2[j]=0;
                }
        }
    }
    return (max*max);
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值