目录
题目1:打家劫舍
思路:
step1:定义子问题
原问题是从n间房屋里偷窃最高金额,我们要求的其实也就是dp[n];
那么子问题,也就是规模更小的问题,原问题是从规模为n间的房屋里偷,所以子问题就可以定义为从规模为n-1,n-2.....间的房屋里偷,也就是dp[k]。
step2:写出子问题的递归关系
怎么去想这个关系呢?
从满足下面两个条件的角度去想:
①原问题能由子问题表示
②子问题又能由更小的子问题表示
这道题怎么通过子问题去表示原问题呢?我们偷n间的房屋的金额,是不是可以表示为1.偷n-1间房屋的金额(最后一间不偷)或者2.偷n-2间房屋的金额+偷最后一间的房屋的金额(倒数第二间不偷)。
因为问的是最大金额,所以从这两种情况中取max值。
step3:确定dp数组的计算顺序
用自底向上的 dp 数组。因为是自底向上,所以我们要确定好递归的终止条件。
代码:
int max(int a,int b){
return a>b?a:b;
}
int rob(int* nums, int numsSize){
if(numsSize==0){
return 0;
}
if(numsSize==1){
return nums[0];
}
int dp[105];
dp[1]=nums[0];
dp[2]=max(nums[0],nums[1]);
int i;
for(i=3;i<=numsSize;i++){
dp[i]=max(dp[i-1],dp[i-2]+nums[i-1]);
}
return dp[numsSize];
}
题目2:零钱兑换
一样的思路:先找出子问题,原问题是金额为n的硬币个数。 所以子问题是比金额n小的金额的硬币个数
代码:
int min(int a,int b){
if(a<=b){
return a;
}
return b;
}
int coinChange(int* coins, int coinsSize, int amount){
int dp[amount+1];
int i,j,min1;
for(i=0;i<amount+1;i++){
dp[i]=amount+1;
}
/* for(i=0;i<coinsSize;i++){
dp[coins[i]]=1;//dp[1]=1//dp[2]=1//dp[5]=1
}*/
dp[0]=0;
for(i=1;i<=amount;i++){
min1=amount+1;
for(j=0;j<coinsSize;j++){
if(coins[j]<=i){
min1=min(dp[i-coins[j]]+1,min1);
}
}
dp[i]=min1;
}
return dp[amount]>amount?-1:dp[amount];
}
题目3:完全平方数
思路:
这道题很好找子问题与原问题的关系:
代码:
class Solution {
public int numSquares(int n) {
int[] dp=new int[n+1];
dp[0]=0;
dp[1]=1;
// dp[2]=2;
// dp[3]=3;
// int max1=Integer.MAX_VALUE;这是我刚开始错误的写法的位置
for(int i=2;i<=n;i++){
int min1=Integer.MAX_VALUE;/*
Integer.MAX_VALUE表示:int 数据类型的最大值,即:2147483647
Integer.MIN_VALUE表示: int数据类型的最小值,即:-2147483648
*/
for(int j=1;j*j<=i;j++){//找完全平方数的方法
min1=Math.min(min1,dp[i-j*j]+1);
}
dp[i]=min1;
}
return dp[n];
}
}