最近在准备面试,当然算法是必不可少的,但是自己平常做的更多的是工程方面的东西,涉及到的最多就是数据结构浅层的东西,还没有花很大的精力来研究算法,但是面试中算法肯定是不可缺少的,所以这几天一直在恶补算法,今天看 算法导论 时看到了动态规划算法,看书怎么也看不懂,于是乎上网搜了一下,结果搜到了知乎上的结果,见知乎之关于动态规划问题的探讨,感觉前两位朋友说的实在是太赞了,不仅是帮我理解了动态规划算法的思想和本质,帮我区分开了递推,贪心,动态规划和搜索的不同,更重要的是他们让我在认识问题上上升到了一个新的高度,即从状态和状态转换来认识IT问题,这实在是太精辟了,很多时候我们解决不了问题就是因为我们看待问题的角度不对,果然思想的高度才是真正的高度啊!!!
下面先总结一下我从上述两位知乎网友的回答中收获的心得:
- 把问题描述的更”IT“一些,也就是用更接近数学和计算机的语言来把原来的实际问题抽象化,这样很有利于我们用更清晰的思路去解决问题
- 在上述进一步抽象的问题描述中找准状态和状态之间的转化关系
- 关于上面说的几种算法思想的区分,这里引用一下上述知乎网友@王勐的回答:
- 每个阶段只有一个状态—>递推(例如Fibonacci数列)
- 每个阶段的最优状态都是由上一个阶段的最优状态得到的—>贪心(例如背包问题)
- 每个阶段的最优状态是由之前所有状态的组合得到的—>搜索(例如迷宫问题)
- 每个阶段的最优状态是由之前的某个阶段的某个状态或者某些状态得到的,并且我们不用管这个状态究竟是怎么得到的—>动态规划(例如我一会要讲的这个问题)
总之真的是有一种“拨开云雾见青天”的感觉啊
接下来就抛出今天我要讲的一个关于动态规划的简单的问题,这个问题也是上述给出的知乎链接网友提出的问题,本着学以致用的目的,在大致理解了动态规划算法之后,我就尝试着用刚学到的知识去解决这个问题,又因为最近刚好在学习python,所以也想通过这个练习巩固一下python的语法,所以这道题目的答案我是用python做的,有兴趣的朋友可以改成C++或者其他语言的,只要理解了解决问题的思路,换成自己熟悉的语言还不是分分钟的事
问题:
给定一个数列,长度为N,求这个数列的最长上升(递增)子数列(LIS)的长度.
以1 7 2 8 3 4为例。
这个数列的最长递增子数列是 1 2 3 4,长度为4;
次长的长度为3, 包括 1 7 8; 1 2 3 等.
解法思路:
首先构造出这个问题的数学模型,即
F_{1} = 1 (根据状态定义导出边界情况)
F_{k}=max(F_{i}+1 | A_{k}>A_{i}, i\in (1..k-1)) (k>1),
其实上面的问题就可以归结为这个公式,有了这个公式就有了更明确的思路了,下标为k时的结果就是下标为k-1时的结果+1(如果[k]元素比k之前的最长递增数列的最后一个数大的话),否则就还是下标为k-1时的结果,这样递归下去,就能得到最终的结果了。
python代码:
python
import math
def longest_sub_increase(list,k):
size = len(list);
if(size==1):
return 1;
if(k==0):
return 1;
max_len = -1;
for index in range(k):
if(list[index]<list[k]):
max_len = max(max_len,longest_sub_increase(list,index)+1);
else:
max_len = longest_sub_increase(list,k-1);
return max_len;
list = [1,2,3,5,1,1];
max_len = longest_sub_increase(list,len(list)-1);
print max_len;
进一步思考一下,那么要是还想把最长的那段数列也打印出来,怎么办呢
这里提出一个比较挫的思路,就是每当确定添加一个元素进入最后的最长数列的时候记录下他的下标,有了这个下标我们就可以重新构造出这个数列了
代码如下:
python
def longest_sub_increase(list,k,route):
size = len(list);
if(size==1):
return 1;
if(k==0):
return 1;
max_len = -1;
for index in range(k):
if(list[index]<list[k]):
new_max_len = max(max_len,longest_sub_increase(list,index,route)+1);
if(max_len < new_max_len):
if(route.count(k)==0):
route.append(k);
max_len = new_max_len;
else:
max_len = longest_sub_increase(list,k-1,route);
return max_len;
list = [1,2,3,1,5,1,1];
max_leno_route = [];
max_len = longest_sub_increase(list,len(list)-1,max_leno_route);
def get_max_route(max_leno_route):
max_leno_route.sort();
route = [];
for index in max_leno_route:
route.append(list[index]);
return route;
print get_max_route(max_leno_route);
print max_len;