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);
}