学习笔记--DP技巧入门 -- 打家劫舍。

 

开头小技巧(先记着):1. dp 分析顺序是 连续 的(注意!逆序 和 顺序)。

                                   2.遇到只分析一个数组的应该 条件反射 想起 以数组 i 为下标 xxx 的最大值。

                     

此题我们可以由繁入简,一开始想着用暴力解如何解决?

我们学过DP思想,可以知道 有三大特性 最优子结构 - 重复子问题 - 无后效性

从爬楼梯 背包问题 等 经典的dp问题中 都可以知道 F(N) = xxx;最左边的 F(N) 表明是 -- 最优子结构,而整个公式表明是 -- 无后效性,那么重复子问题在哪呢?就在我们分析的 暴力解 中。


进入本题!

我们围绕着上述的经典dp的 背包问题开始这道题的分析:

由于给的每家的钱数都是正整数,则每次偷家的钱应该是:F(n) = Max( 之前的偷钱 (起始为0) + 当前偷的钱 );

表格表示暴力解(遍历每一种可能性):

          选择任意个作为偷家起点这里我们选择第一个

     i = 12345
数组 =

2

7931max
i=1

2     

0       

0

   

 0

          

02
i=2

2

0+2=0(相邻偷不了)

7(当前的钱)

0 0 02
i=3

2

7

9+2=11

9+7=9(相邻偷不了)

   0011
i=4

2

711

3+7=10

3+11=3(不能偷相邻的11)

011
i=5271110

1+11=12

1+2=3

1+7=8

12

单纯以第一个为起点后,12 是偷到最多的 答案自然而然是 12.(只针对以起点为2的,答案正确只是碰巧)


进入DP分析(利用 开头技巧1 分析):

作为小偷的你,限制 你为所欲为 的唯一条件是:“不能偷相邻的房屋”。这里就产生了 偷 与 不偷 的问题 对应 背包问题中的 放 与 不放。 偷产生一种可能,不偷产生另一种可能 也就分析出 产生了-->   重复子问题

这里呼应 开头提供的技巧2,则可以得 每个数组下标的值 表示当前所偷钱的最大值。所以我们只需要F(N) 与之前的最大值相加就可以得到答案 -->   最优子结构。

由上述表格,每个相加可以都应该选择最大的值 ,依次叠加,只影响后面,不影响前面, 可以分析出 F(i) = F(i) + Max (    F(0..i - 1)  );( 此公式相加后 并不会 对前面的值 F(0..i - 1)   )造成任何影响;-->  可得 无后效性。

设 max1 是 i - 1前 最大的值的下标, max2 是i - 1 前 第二大的值的下标, F(i) 是: 下标为 i 的值;

由此可得状态转移 dp公式:1. F(i) = F(i) +  F(max1)(max1 !=  i - 1);

                                             2. F(i) = F(i) +  F(max2)(max1 == i - 1);

class Solution {
    //要明白每个下标的值表示:能偷到钱数的最大值。
    public int rob(int[] nums) {
        int n = nums.length;
        if (n == 1) return nums[0];//只能抢一家
        int max1 = nums[0] < nums[1] ? 1 : 0;
        int max2 = max1 == 1 ? 0 : 1;
        for (int i = 2; i < n; i++) {
            nums[i] += nums[max1 != i - 1 ? max1 : max2]; //2.如果抢到金额最大值相邻(i - 1)的话,那就去抢之前的最大值。
            if (nums[max1] < nums[i]) {
                max2 = max1; //1.保存之前的最大值。
                max1 = i;
            }
        }
        return nums[max1];
    }
}

ps:大二菜鸡一枚,第一次写博客,写得有错误  欢迎指正!

上面开头的两个小技巧 是 自己最近刷dp题 的感觉,就是那种只可意会不可言传,你懂吧?~ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值