入门线性dp

文章介绍了动态规划中的线性DP方法,通过三个具体的LeetCode题目——最小花费爬楼梯、打家劫舍和删除并获得点数,阐述了解决这类问题的基本步骤:设计状态、状态转移方程、初始化和执行转移,最后返回解。每个题目都提供了AC代码示例,展示如何应用状态转移方程找到最优解。

写博客只为了巩固已学知识,如有问题欢迎大家指出。

   关于基本线性dp,属于动态规划的一种,其解决问题的基本方法的通解一般为以下几点:

                1.设计状态

                2.写出状态转移方程(这个与递推有点相似)

                3.确定初始状态(初始化数据)

                4.执行状态转移

                5.返回问题所需的解

下面用题目举例子说明

​​​​​746. 使用最小花费爬楼梯 - 力扣(LeetCode)      

  第一题题解:

     我们用一个数组来表示状态:f[i]表示爬到第i层楼梯的最小花费,由于每次只能爬1层或者2层楼梯,所以f[i]这个状态只能从f[i - 1]或者f[i -2]转移来,那么情况就可以分为两类

        (1)假如从i- 1 层爬上来的话 , 那么所需的花费应当是f[i - 1] + cost[i - 1]

        (2)假如从i- 2 层爬上来的话 , 那么所需的花费应当是f[i - 2] + cost[i - 2]

情况只有这两种,现在我们只需考虑最小花费的一种情况,就是这两种情况取小,然后我们就可以得到这个状态转移方程        f[i] = min ( f[i - 1] + cost[i - 1]  ,  f[i - 2] + cost[i - 2])                          最后别忘了初始化数据f[0]  f[1]  ,起始条件可以任选楼梯 ,所以花费是f[0] = 0  f[1] = 0

附上AC代码:

        

int min(int a, int b){
    return a < b ? a : b;
}


int minCostClimbingStairs(int* cost, int costSize){
    int f[1001] = {0 , 0};
    for(int i = 2 ;  i <= costSize ; i++){
        f[i] = min(f[i - 1] + cost[i - 1] , f[i -2] + cost[i -2]);
    }
    return f[costSize];
} 

 198. 打家劫舍 - 力扣(LeetCode)      

   第二题题解:

             比第一题稍微难一点,但是题目思路还是差不多,都是寻找状态方程(这个是最重要的)

        定义一个数组dp[i]表示:偷前 i 间房子能得到的最大值。

        假设有 A  B  C  D  E 这几间房子 ,合法情况有如下两种:

                 (1)最后选择偷E房子,那么D肯定不能选 , 于是dp[E]最后的结果应当是dp[C],最后结果就是num[E] + dp[C]

                 (2)最后不选择偷E房子 , 那么最后情况就是dp[D]

在这两种间选择最大的 ,于是我们可以知道状态转移方程就是:

                                dp[i] = max ( dp[i - 1]  , num[i ] + dp[i - 2])

同样的初始化别忘了 , 如果只有一间房子,那么可以直接返回num[0].  若房子多于2间 ,那么dp[0] = num[0]  dp[1] = max(num[0] , num[1])

附上AC代码:

int max(int a , int b){
    return a > b ? a : b;
}

int rob(int* nums, int numsSize){
    int dp[101];
    if(numsSize == 1){
        return nums[0];
    }
    dp[0] = nums[0];
    dp[1] = max(nums[0] , nums[1]);
    for(int i = 2 ; i < numsSize ; i++){
        dp[i] = max(dp[i - 1] , nums[i] + dp[i - 2]);
    }
    return dp[numsSize - 1];
}

​​​​​​​​​​​​

740. 删除并获得点数 - 力扣(LeetCode)

 

第三题题解:

    这题如果不放在动态规划上我应该很难联系上来。

   根据题意,在选择了元素 x 后,该元素以及所有等于 x−1或 x+1的元素会从数组中删去。若还有多个值为 x 的元素,由于所有等于 x−1 或 x+1 的元素已经被删除,我们可以直接删除 x并获得其点数。因此若选择了 x,所有等于 x 的元素也应一同被选择,以尽可能多地获得点数。我们可以直接把原数组的元素放进一个哈希表中去,然后直接对这个哈希表进行一个如同第二题的一个打家劫舍(这个题就是第二题打家劫舍的一个变式)

附上AC代码:

int hash[10001] , dp[10001];

int max(int a,int b){
    return a > b ? a : b;
}

int deleteAndEarn(int* nums, int numsSize){
    memset(hash , 0 , sizeof(hash));
    for(int i = 0 ;  i < numsSize ; i++){
        hash[nums[i]] += nums[i];
    }
    dp[0] = 0;
    dp[1] = hash[1];
    for(int i = 2 ; i <= 10000 ; i++){
        dp[i] = max(dp[i - 1] , dp[i - 2] + hash[i]);
    }
    return dp[10000];
}

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值