由一道笔试题看动态规划

对于大多数学习编程的人来说,动态规划一直是一个难突破的点,我自己在学习过程中也是很困惑,各种书籍资料,视频都看过不少,基本的思想也都能理解,但一碰到题目的时候还是觉得无从下手。最近在做笔试题的时候突然有了一丢丢理解,这里记录下, 没准路过看到的人能加深理解或有所启发。

逆向思维

题目如下:

一个人在 m×n 的方格里行走,每次只能向右或向下,每个方格里的值是距离,求从起点走到终点的最短路径值。
示例:3 3
1 3 1
1 5 1
4 2 1
最终输出 7 ,从左上走到右下所花费的最短距离是 7

第一眼看到题目的时候,就知道是动态规划类的题了,然而在做题时由于各(tai)种(cai)原(le)因还是没能做出来,尽管对这种类型的题目见得多了。有种我熟悉它它却不待见我的赶脚。等到结束之后回过头来想,想啊想啊想 ... 半小时过去了,又想啊想,总算是把代码实现出来了。

按照正常思维来看的话,人站在起点处,向右或向下走到终点,那么最短距离就是每次比较向左或向下的路程,取最小的走,在加上自身需要的路程,这样一直走到终点就是最短的路径值。对照着题目验证下,那就是 1 -> (向下) 1 -> (向下) 4 -> (向右) 2 -> (向右) 1 到达终点,总距离是 9 ,发现这种走法是错的。正确的走法应该是 1 -> 3 -> 1 -> 1 -> 1 ,总距离是 7 最短。

image

此方法不行,那我们来考虑第二种解法。现在,不从起点来推算了,因为我们一眼看过去题目这个矩阵,就知道在这个输入下,最好的路径就是 1 -> 1 -> 1 -> 3 -> 1 这样走法,怎么得出来的呢?我们从矩阵最后一个数看,它是终点,那这个终点是如何过来的呢? 发现它是由左边或者上边这个数字过来的,为什么会这样?因为题目说了,只能向右或向下走,所以终点的这个位置要么是上面位置向下走得来的,要么就是左边位置向右走到达的。所以我们从后往前推得出 1 -> 1 -> 1 -> 3 -> 1 这种最佳走法。如下图:

image

这就是传说中的动态规划 , 在这道题里,我们定义的一个状态是 f(i, j) ,表示从起点走到坐标(i, j) 所经历的最短路径,由上面的推断可以发现,坐标 (i,j)的最短路径总是由 坐标(i-1, j) 和坐标 (i, j-1) 两个的最小值加上坐标 (i, j) 自身的值得来
状态转移方程为 f(i, j) = Math.min(f(i-1 ,j), f(i, j-1)) + values[i, j] i, j 为二维数组的坐标,values 为数组对应坐标的初始值。原始数组 values 和 dp 数组的推算值如下图:

image

有了上面的铺垫,我们就可以得出代码了:

function solve(arr, m, n) {
    //定义一个二维数组 dp , dp[i][j]表示走到i,j这个点的最短路径
    var dp = new Array(m);
    for (var i = 0; i < m; i++) {
        dp[i] = [];
        for (var j = 0; j < n; j++) {
            dp[i][j] = 0;
        }
    }
    // 初始化第一行和第一列的状态值
    dp[0][0] = arr[0][0];
    for (var i = 1; i < n; i++) {
        dp[0][i] = arr[0][i] + dp[0][i - 1];
    }
    for (var i = 1; i < m; i++) {
        dp[i][0] = arr[i][0] + dp[i - 1][0];
    }
    // 动态规划,计算每个点的最短路径值
    for (var i = 1; i < m; i++) {
        for (var j = 1; j < n; j++) {
            dp[i][j] = arr[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]);
        }
    }
    return dp[m - 1][n - 1];
}

我们用一个二维数组dp , 来存储每个节点的最短路径值,这里要特别注意的是,需要对数组的第一行和第一列进行初始化,第一行的每个点只能由左边向右走过来,所以直接累加相应坐标的值;同理第一列的每个点只能由上面向下走得来,每个点由原来的值加上一个点的值即可。接下来从第 1 行,第1列开始,一直遍历到 m -1, n -1 ,把每个状态值填上,函数的返回值为走到终点的坐标也就是 dp[m-1][n-1] 。

动态规划的思想

在学习动态规划的时候,学的一愣一愣的,什么最优子结构、无副作用、重复子问题等,看着这些理论似懂非懂。

什么是动态规划?我觉得动态规划就是逆向,由后往前地去推导这样的过程,就仿佛开了上帝视角一样,在已经知道结果的情况下,通过对各种情况的抉择,去倒推出原始的起点,然后定义一个合理的状态来解释。像上面的这道题目,问你一个人从左上角走到右下角的最短路程,那我们在看题的时候,可以全局地看到各个路径的距离值以及周围的路径分布,所以可以通过推算很快得出结果。上面的第一种解法其实就是贪心的思路,从起点开始,每次选择一条最短的路径走下去,这样带来的弊端就是可能后面的路径是更加糟糕的,容易因为短视而得不到最佳的结果。

总的来说,在遇到一些求最佳问题时,比如求最短路径,最大价值、最长公共子序列等问题时,就要考虑使用动态规划来求解,而有些时候,不妨先用贪心的思想来试试能否求得结果,这样也能明白不行的原因在哪里,也能加深对动态规划的应用场景理解。

后记

很多时候看懂了不一定真的懂了,正如开头提到的知道题目是动态规划,但就是觉得无从下手,现在看还是要多做多理解,也许过段时间又有新的领悟。

对这个知识点的理解还有待加深,文章有什么不对之处,敬请指正,欢迎交流探讨。

(完)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357

推荐阅读更多精彩内容

  • 回溯算法 回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并...
    fredal阅读 13,667评论 0 89
  • 教程基本框架和部分内容转自Hawstein 出处:http://hawstein.com/posts/dp-nov...
    Wallace_QIAN阅读 1,143评论 2 3
  • 动态规划 动态规划是一种高性能的牛逼算法,由美国的R.Bellman提出,它是动态就是体现在此算法是基于一个递推公...
    董泽平阅读 1,171评论 0 12
  • 娃昨天滑冰没玩过瘾,今天能玩雪,激动得两眼放光! 中午到达滑雪场,午饭没顾上吃,滑雪板也没套上,娃就在雪地里撒欢地...
    Wendy徐阅读 800评论 2 2
  • 冬天的太阳离我有多远,我自私的把她揽入怀中,想抱紧她,她却从我的指缝中溜走,似乎爱是一个负担。
    小兵兵陈阅读 120评论 0 0