剑指offer14剪绳子(无数学推导) 顺便谈谈动态规划

《剑指offer》中,第14题,剪绳子是一个引子,引出了动态规划和贪婪算法。
“动态规划”一词显得十分高深,当时上学的时候就不是很理解。现在多多少少比当时有所进步,看了书之后,感觉理解比之前要深了,现在把这些理解分享出来。

首先不要怕,别管它为什么叫“动态规划”,你也不用想怎么才能动态,如何才能规划,这只是个名字而已,叫他什么都行。
书中讲了动态规划的四个特点,总结如下:
1:目的是求最优解
2:最优解依赖于子问题的最优解
3:大问题可以分解成小问题,这些小问题之间有重叠
4:从下往上求解

现在来一一解释一下,第一条,目的是求最优解,这种情况下,不只是让求解,而是让求问题的最优解。

第二条概括来说就是“千里之行始于足下”和“勿以善小而不为”,我们既然要实现大问题的最优解,那么我们一定要把眼前的事做好,每一步都走好,最终到达终点时我们才是以最优地方法到达。

第三条,前半句不说了,后半句是说,子问题之间会有重叠,因为问题分解小了,有些子问题是重复的,这样就不要重复计算了,所以一般动态规划都会有一个数组来保存子问题的最优解。

第四条,从下往上求解,如果理解了前三条,第四条就好理解了,因为最优解是依赖子问题的最优解的,所以一定要先从简单的问题开始解决。小问题解决了,大问题就迎刃而解了。

先看题,边看边说。

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

提示:

2 <= n <= 58

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

按照上面的四个特点来跟题目对下,

第一条,最优解,题目也是要求乘积最大

第二条,大问题最优解取决于子问题,我们先切一刀,变成两根绳子了,那么乘积最大值是这两段各自的最大值之积,那么这两段绳子的最优解又依赖它们各自的子绳段。

第三条,各个小问题之间存在重叠,是不是这样的呢?可以想到,当我们的绳子切得足够段,一定会出现相同的情况,这些就是重叠的部分。

第四条,就是我们要看到的,我们必须从绳子长度为1 2 3 4开始推,因为长度为 5 6 7 8 9的最优解是依赖他们的。

我们首先要解决几个特殊解,长度为0,答案是0,长度为1,答案也是0,长度为2,答案为1,长度为3,答案为2。

先看代码再答疑。

class Solution {
public:
    int cuttingRope(int n) {
        if (n <= 0) return 0;
        if (n == 1) return 1;
        if (n == 2) return 1;
        if (n == 3) return 2;
        int max_table[n+1] ;
        max_table[0] = 0;
        max_table[1] = 1;
        max_table[2] = 2;
        max_table[3] = 3;
        for(int i = 4 ; i <= n ; i++){
            int max = 0;
            for(int j = 1; j <= i/2; j++){
                if(max_table[j]*max_table[i-j]>max)
                    max = max_table[j]*max_table[i-j];                    
                max_table[i] = max;
            }
        }
        return max_table[n];
    }
};

首先是几个特殊解。

接下来要建一个表格,用来保存子问题的最优解。

肯定有不少同学认为,前几个最优解就是我们开始给的特殊解,其实并非如此。

对于这点的解释,leetocode上的题解给了很多数学推导,但并没从实际问题上做出解释,数学是实际问题的抽象,如果数学推导的通,那么也应该可以给出合理的解释。

table:   i    0   1   2   3   4
       value  0   1   2   3   4

这里的 i 该如何理解,才能更好地解释这个问题呢,如果 i 代表绳子的长度,那么i = 4时,我们可以很好的理解,那么 i = 3的时候就不好理解了,长度为3,最优解应该是2呀,对不对。

其实,我们可以这样想,每一位上的数,并非说单单指长度为 i 时的结果,而是要表示当前绳子长度为 i 时,与另一端长度为 j 的绳子做乘积时,所能提供出来的最大值。当绳子本身已经是子绳段时,可以不切了(与特殊解不一致是因为绳子必须得切),把自己本身的长度直接给对方去乘,也就说, 其实 i 所对应的value 是

max(i, i 的子问题最优解)

以 3和5 为例

tabel[3] = max(3,table[1]*table[2]) = 3
table[5] = max(5,table[2]*table[3]) = 6

只不过,我们会发现,当 i 的数字越大时,子问题的乘积会远远大于本身。如果理解了这个表格的真正含义,那么这个问题就不在话下了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值