【刷题笔记】--dp--完全背包

目录

题目1:打家劫舍

题目2:零钱兑换

题目3:完全平方数 

 


题目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];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值