【干货】动态规划十问十答

问1:动态规划是个什么鸟蛋?

答:动态规划是一种通过“大而化小”的思路解决问题的算法。区别于一些固定形式的算法,如二分法,宽度优先搜索法,动态规划没有实际的步骤来规定第一步做什么第二步做什么。所以更加确切的说,动态规划是一种解决问题的思想。这种思想的本质是,一个规模比较大的问题(假如用2-3个参数可以表示),是通过规模比较小的若干问题的结果来得到的(通过取最大,取最小,或者加起来之类的运算)所以我们经常看到的动态规划的核心——状态转移方程都长成这样:

* f[i][j] = f[i - 1][j] + f[i][j - 1]

* f[i] = max{f[j] if j < i and …} + 1

* f[i][j] = f[0][j - 1] && judge(1,i) || f[1][j - 1] && judge(2,i) || …

问2:动态规划面试考得多么?

答:多,并且越来越多。随着CS从业与求职者的增加,并伴随大家都是“有备而来”的情况下,一般简单的反转链表之类的题目已经无法再在面试中坚挺了。因此在求职者人数与招聘名额的比例较大的情况下,公司会倾向于出更难的面试问题。而动态规划就是一种比较具有难度,又比较“好出”的面试问题。相比其他的算法与数据结构知识来说,贪心法分治法太难出题了,搜索算法往往需要耗费求职者过长的程序编写时间一般也不倾向于出,二叉树链表等问题题目并没有那么多,而且求职者也都会着重准备这一块。因此动态规划这一类的问题,便越来越多的出现在了面试中。

问3:动态规划快在哪儿?

答:动态规划一般来说是“高效”的代名词,因为其解决的问题一般退而求其次的算法只有搜索了。以“数字三角形”一题为例子(http://www.lintcode.com/problem/triangle/ ),在“三角矩阵”中找一条从上到下的路径,使得权值之和最小。如果使用暴力搜索的算法,那么需求穷举出2^(n-1)条路径(n为三角形高度),而使用动态规划的话,则时间复杂度降低到了n^2,完成了质的飞跃。那么究竟为什么这么快呢?原因在于动态规划算法去掉了“无用和重复的运算”。在搜索算法中,假如从A->B有2条路径,一条代价为10,另外一条代价为100,B->终点有1024条路径。当我们选择了代价为10的那条路径走到B时,可以继续往下走完1024条路径到终点,但是在此之后,我们再从代价为100的路径从A走到B时,我们可以发现此时无论如何走,都不可能有刚才从10的路径走过来更好,所以这些计算是“无用”的计算,也可以说是“重复”的计算。这就是动态规划之所以“快”的重要原因。

问4:学习动态规划有什么捷径?

答:我们将动态规划的常见类型分为如下几种:

* 矩阵型

* 序列型

* 双序列型

* 划分型

* 区间型

* 背包型

* 状态压缩型

* 树型

其中,在技术面试中经常出现的是矩阵型,序列型和双序列型。划分型,区间型和背包型偶尔出现。状态压缩和树型基本不会出现(一般在算法竞赛中才会出现)。

每种类型都有着自己的题目特点和状态的表示方法。以矩阵型动态规划为例,一般题目会给你一个矩阵,告诉你有一个小人在上面走动,每次只能向右和向下走,然后问你比如有多少种方案从左上走到右下 (http://www.lintcode.com/problem/unique-paths/)。这种类型状态表示的特点一般是使用坐标作为状态,如f[i][j]表示走到(i,j)这个位置的时候,一共有多少种方案。状态的转移则是考虑是从哪儿走到(i,j)这个坐标的。而序列型的动态规划,一般是告诉你一个序列;双序列的动态规划一般是告诉你两个字符串或者两个序列。

将所做过的动态规划问题按照这些类别进行归类,分析状态的表示方法和状态转移方程的构造方法在每种类型中的近似之处,会让你更快的学会动态规划。

问5:什么样的问题适合使用动态规划?

答:可以使用动态规划的问题一般都有一些特点可以遵循。如题目的问法一般是三种方式:

1. 求最大值/最小值

2. 求可不可行

3. 求方案总数

如果你碰到一个问题,是问你这三个问题之一的,那么有90%的概率是使用动态规划来求解。

要重点说明的是,如果一个问题让你求出“所有的”方案和结果,则肯定不是使用动态规划。

问6:解决一个动态规划问题的步骤是什么?

答:首先根据“问5”判断是否是动态规划的问题,如果是,则尝试将其按照“问4”进行分类,找到对应的类别和相似的问题。接着从下面的4个要素去逐步剖析解决这道题:

1. 状态是什么

2. 状态转移方程是什么

3. 状态的初始值是什么

4. 问题要求的最后答案是什么

每个步骤分析完成之后,就基本上解决了整道动态规划的问题。

问7:怎样优化动态规划的时间?

答:一般来说,使用动态规划求解的问题,时间上已经比暴力搜索要优化很多了。但是仍然存在着一些可以优化的空间。通常来说,动态规划的时间优化,有如下两种常见的方式:

1. 通过变换状态优化

2. 通过决策单调优化

对于通过变换状态来优化的问题比较难,需要一些经验和灵感。而对于决策单调的优化,则比较简单,但适用范围不广,一般只适用于划分型动态规划当中,通常这个方法可以将复杂度降低一个数量级。

问8:怎样优化动态规划的空间?

答:动态规划的空间优化只有一种方法,就是使用滚动数组进行优化。以一个二维的动态规划为例子。假如状态转移方程如下:f[i][j] = f[i - 1][j] + f[i][j - 1]。我们可以发现,第i层的状态,已经和第i-2层的状态没有关系了,那么这种情况下,用于存储第i-2层的空间就可以被重复利用。方法非常简单,把数组的第一维对2取模就可以了:f[i % 2][j] = f[(i - 1) % 2][j] + f[i % 2][j-1]。这种方法通常可以将空间复杂度降低一个数量级。

问9:有什么动态规划的书籍和参考资料可以推荐么?

yuanbin的gitbook:

http://algorithm.yuanbin.me/dynamic_programming/index.html

著名的背包九讲:

http://love-oriented.com/pack/

http://vdisk.weibo.com/s/tanGyi7qM8TVE

(也可以直接在网上搜索背包九讲)

问10:有哪些动态规划题目必须要练习的?

在LintCode上包含了30余道动态规划的练习题,都是从实际的面试问题中汇总的精选练习:

http://www.lintcode.com/tag/dynamic-programming/

想要更加扎实的学习动态规划算法么?

本文作者主讲的九章算法班火热报名中!

北京时间7.19周日早9:30-11:30(美西时间7.18周六晚6:30),第一节课免费试听!

报名请戳:http://www.jiuzhang.com/course/1/

——————

版权声明

本文作者:九章算法段老师,九章算法班主讲人。

九章算法,提供算法培训、IT求职咨询,帮助更多中国人找到好工作。

本文属九章算法版权所有,转载请注明以上声明。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 21:19:06

【干货】动态规划十问十答的相关文章

干货:图解算法——动态规划系列

小浩:宜信科技中心攻城狮一枚,热爱算法,热爱学习,不拘泥于枯燥编程代码,更喜欢用轻松方式把问题简单阐述,希望喜欢的小伙伴可以多多关注! 动态规划系列一:爬楼梯 1.1 概念讲解 讲解动态规划的资料很多,官方的定义是指把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解.概念中的各阶段之间的关系,其实指的就是状态转移方程.很多人觉得DP难(下文统称动态规划为DP),根本原因是因为DP区别于一些固定形式的算法(比如DFS.二分法.KMP),没有实际的步骤规定第一步第二步来做什么,所以准

最大连续子序列和-动态规划

题目描述: 给定K个整数的序列{ N1, N2, -, NK },其任意连续子序列可表示为{ Ni, Ni+1, -, Nj },其中 1 <= i <= j <= K.最大连续子序列是所有连续子序中元素和最大的一个, 例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20. 注意: 最大连续子序列和如果为负,则返回0:而本题目中的最大连续子序列和并不返回0,如果是全为负数,则返回最大的负数即可. 思路分析: -具有

LCS问题(最长公共子序列)-动态规划实现

问题描述: 问题] 求两字符序列的最长公共字符子序列 注意: 并不要求子串(字符串一)的字符必须连续出现在字符串二中. 思路分析: 最优子结构和重叠子问题的性质都具有,所以要采取动态规划的算法 最长公共子序列的结构 设序列X= 其中Xm-1= 子问题的递归结构 由最长公共子序列问题的最优子结构性质可知,要找出X= 由此递归结构容易看到最长公共子序列问题具有子问题重叠性质. 例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1及Xm-1和Y的最长公共子序列.而这两个子问题都包含一个公共子

Leetcode 494 Target Sum 动态规划 背包+滚动数据

这是一道水题,作为没有货的水货楼主如是说. 题意:已知一个数组nums {a1,a2,a3,.....,an}(其中0<ai <=1000(1<=k<=n, n<=20))和一个数S c1a1c2a2c3a3......cnan = S, 其中ci(1<=i<=n)可以在加号和减号之中任选. 求有多少种{c1,c2,c3,...,cn}的排列能使上述等式成立. 例如: 输入:nums is [1, 1, 1, 1, 1], S is 3. 输出 : 5符合要求5种

活动选择的贪心算法与动态规划(未完成)

// greedy_algorithm.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include<queue> using namespace std; #define NofActivity 11 int c[NofActivity + 1][NofActivity + 1]; int reme[NofActivity + 1][NofActivity + 1]; //活动的

求不相邻金币相加和的最大值--动态规划1

求不相邻金币相加和的最大值. 输入n个金币的金币面值(正数自定义),求这些金币不相邻和的最大值. 动态规划问题1 设f(n)为第n个金币数的最大值,f(0)=0,f(1)=a[1],输入的数组从下标为1开始. f(n)=max{a[n]+f(n-2),f(n-1)}. 代码如下: import java.util.Scanner; public class Jin_bi_zui_da_zhi { public static void main(String[] args) { Scanner s

你那么喜欢看“干货”,是因为你根本没想做什么努力

前几天朋友问我,能不能分享一下我自己写作方面的干货或者经验.我特别害怕这样的问题,因为我并不是一个喜欢总结方法论的人.我只能跟你说,要不断的写,写作特别辛苦也需要特别勤奋,很多常人看不见的努力你必须下得到.但这样的说法通常不会让人满意,总觉得我在保留自己的迷茫,害怕别人超过自己而回答的模棱两口. 但事实上来讲,我周围的写作者是什么样的呢? 白天上班,晚上写作到半夜是常有的事儿;在外面用手机写,在机场等飞机也在写,不断的看书,疯狂的阅读.他们没多少人去关注什么干货或者技巧,就是疯狂的写而已.我的朋

【干货】如何使用C++11实现C#属性概念设计

目录(原创博客,版权所有,转载请注明出处 http://www.cnblogs.com/feng-sc) 1.概述 2.C#属性的概念  2.1.简单示例代码介绍C#中的属性  2.2.C++实现效果与C#效果对比(熟悉C#属性读者可从此小节开始) 3.如何使用C++11实现C#属性的概念模型 3.1.property_rw介绍 3.2.property_r.property_w介绍 3.3.完整属性测试代码介绍 4.总结 1.概述 本人对“C++实现C#属性概念”的研究决定并非一时冲动,而是原

【Bugly干货】关于 Android N 那些你不知道的事儿

今年3月,Google 破天荒提前半年发布了 Android N 开发者预览版.当然,作为一个不合格的谷粉并没有第一时间体验安装,因为至今仍然能够回忆起来去年今日此门中(雾)兴冲冲刷了 Android M Preview 的时候发现各种 Crash就连微信也(不出所料得)中招时自己一脸懵逼的心情.当然,为自己的机智而庆幸并没有过多久,很快就有微信好友(当然也是纯纯的谷粉)反馈微信又双叒叕在 Android 新版本下Crash了……好吧这次我们的时间很充裕,因为 5 个 preview 之后才会发