LCP 07. 传递信息
awsl,建立动态方程好难阿,我还得在纸上画,然后慢慢推。这个当时没做,幸好我直接关掉那个比赛界面,不然感觉纯粹浪费时间。dp[k][n-1]里存储的表示经过K步到编号为n-1的小朋友的路径数。
int numWays(int n, int** relation, int relationSize, int* relationColSize, int k){//技术型的DP
const int row=k+1;
const int col=n;
int dp[row][col];
memset(dp,0,sizeof(dp));
dp[0][0]=1;//这个初始值也很重要
for(int i=1;i<row;++i){//因为要求必须传递,所以k至少为1
for(int j=0;j<relationSize;++j)
//relation[j][1]为目的地,而relation[j][0]为其前一步
dp[i][relation[j][1]]+=dp[i-1][relation[j][0]];
}
return dp[k][n-1];
}
53. 最大子序和
数组增益,其实和注释里的动态方程是一个思想。只不过这样使用的空间小写。
我自己的思维,是一直在意nums[i]对前面和的影响。
而实际是,注意前面和的正负对后面的影响,思维顺序是返的。OMG
#define MAX(x, y) ((x) > (y)) ? (x) : (y)
int maxSubArray(int* nums, int numsSize){//数组增益对后面的影响
int res=nums[0],i,sum=0;//用sum记录num[i]未参与运算之前的和
for(i=0;i<numsSize;i++){
if(sum>0)
sum+=nums[i];
else
sum=nums[i];
res=MAX(res,sum);//动态方程dp[i]=MAX(dp[i-1]+num[i],num[i])
}
return res;
}
322. 零钱兑换
第一话:我要死了,动态规划完全不熟悉,我已经ger屁了。
第二话:我注释的代码,是我整了两个小时,只通过1/3用例的代码,调试了一遍,如果硬币种类中没有1的话,那我的代码就死了,嗯,死了。
第三话:我自己用的二维来解的,后来发现一维就行,因为前面那些行的数据根本就用不到。
最终图解(先看第一张,再看第二张,或许能懂)
int Min(int a,int b){
return a<b? a:b;
}
int coinChange(int* coins, int coinsSize, int amount){//coinsSize为行数,amount为列数
//这是硬币种类被限制,但是每种硬币的数量是没有限制的
/*int **dp=(int **)malloc(sizeof(int *)*(coinsSize+1));
int i,j;
for(i=0;i<=coinsSize;i++){
dp[i]=(int *)malloc(sizeof(int)*(amount+1));
memset(dp[i],0,sizeof(int)*(amount+1));
}
for(j=0;j<=amount;j++){
if(j<coins[0])
dp[0][j]=0;
else
dp[0][j]=INT_MAX;
}
for(i=1;i<=coinsSize;i++){
for(j=1;j<=amount;j++){
if(j>=coins[i-1])
dp[i][j]=Min(dp[i-1][j],dp[i][j-coins[i-1]]+1);
else
dp[i][j]=dp[i-1][j];
}
}
if(dp[coinsSize-1][amount]==0)
return -1;
else
return dp[coinsSize][amount];*/
if(amount==0)
return 0;
int *dp=(int *)malloc(sizeof(int)*(amount+1));
memset(dp,0,sizeof(int)*(amount+1));
int i,j,min;
for(i=0;i<coinsSize;i++){
for(j=coins[i];j<=amount;j++){
if(j==coins[i])
dp[j]=1;
else if(dp[j]==0&&dp[j-coins[i]]!=0)
dp[j]=dp[j-coins[i]]+1;
else if(dp[j-coins[i]]!=0)//注意这个地方我第一次写的dp[j]!=0。dp[j-coins[i]]==0代表不存在组合,直接跳过不变就行
dp[j]=Min(dp[j],dp[j-coins[i]]+1);
}
}
min=dp[amount];
free(dp);
return min==0? -1:min;
}
518. 零钱兑换 II
这题是找组成total有多少种方案
int change(int amount, int* coins, int coinsSize){
if(coinsSize==0&&amount!=0)
return 0;
else if(coinsSize==0&&amount==0)
return 1;
int i,j;
int *dp=(int *)malloc(sizeof(int)*(amount+1));
memset(dp,0,sizeof(int)*(amount+1));
for(j=0;j<=amount;j++){
if(j%coins[0]==0)
dp[j]=1;
}
for(i=1;i<coinsSize;i++){
for(j=coins[i];j<=amount;j++){
dp[j]=dp[j]+dp[j-coins[i]];
}
}
return dp[amount];
}
64. 最小路径和
int minPathSum(int** grid, int gridSize, int* gridColSize){//先把第一行第一列算出来
if(gridSize==0)
return 0;
int i,j;
for(i=1;i<gridSize;i++){
grid[i][0]+=grid[i-1][0];
}
for(j=1;j<*gridColSize;j++){
grid[0][j]+=grid[0][j-1];
}
for(i=1;i<gridSize;i++){
for(j=1;j<*gridColSize;j++){
if(grid[i-1][j]<grid[i][j-1])
grid[i][j]+=grid[i-1][j];//状态转移方程
else
grid[i][j]+=grid[i][j-1];
}
}
return grid[gridSize-1][*gridColSize-1];
}
70. 爬楼梯
分析一下,就是典型的Fibonacci。不好的是,我用递归超时了,然后换成下面的。
int climbStairs(int n){
if(n<=2)
return n;
int pre1=1,pre2=2,i,cur;
for(i=2;i<n;i++){
cur=pre1+pre2;
pre1=pre2;
pre2=cur;
}
return cur;
}