携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情
动态规划(DP)是什么
动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。
20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。
动态规划的特点
动态规划最核心的思想,就在于拆分子问题,记住过往,减少重复计算。
分析是从大到小,写代码是从小到大。计算过程中会把结果都记录下,最终结果在记录中找到
LCS(最长公共子序列)
一个序列A任意删除若干个字符得到新序列B,则A叫做B的子序列
两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列
最长公共子序列(LCS)-〉 是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。这与查找最长公共子串的问题不同的地方是:子序列不需要在原序列中占用连续的位置。而最长公共子串(要求连续)和最长公共子序列是不同的
LCS的应用场景
- 相似度的比较:计算生物学DNA对比(亲子验证),,,百度云盘找非法数据
- 图形相似处理,媒体流的相似比较,百度知道,百度百科,,WEB页面中找非法言论
LCS的解决办法
- 穷举法(实际应用中不可取)
- 动态规划
动态归法算法解决LCS的思路:
以两个序列 X、Y 为例子:
设有二维数组f[i,j] 表示 X 的 i 位和 Y 的 j 位之前的最长公共子序列的长度,则有:
f[1][1] = same(1,1);
f[i,j] = max{f[i-1][j -1] + same(i,j),f[i-1,j],f[i,j-1]};
其中,same(a,b)当 X 的第 a 位与 Y 的第 b 位相同时为“1”,否则为“0”。
此时,二维数组中最大的数便是 X 和 Y 的最长公共子序列的长度,依据该数组回溯,便可找出最长公共子序列。
代码编写
/**
* LCS算法
*/
public static int max(int a,int b){
return (a>b)?a:b;
}
public static void getLCS(String x,String y){
char[] s1=x.toCharArray();
char[] s2=y.toCharArray();
int[][] array=new int[x.length()+1][y.length()+1];
//先把第一行和第一列填上零
for (int i = 0; i < array[0].length; i++) {
array[0][i]=0;
}
for (int i = 0; i < array.length; i++) {
array[i][0]=0;
}
//使用动态规划的方式填入数据
for (int i = 1; i < array.length; i++) {
for (int j = 1; j < array[i].length; j++) {
if(s1[i-1]==s2[j-1]){//如果相等,左上角加1填入
array[i][j]=array[i-1][j-1]+1;
}else{
array[i][j]=max(array[i-1][j],array[i][j-1]);
}
}
}
//打印
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]+" ");
}
System.out.println();
}
//从后往前找到结果
Stack result=new Stack();
int i=x.length()-1;
int j=y.length()-1;
while((i>=0) && (j>=0)){
if(s1[i]==s2[j]){
result.push(s1[i]);
i--;
j--;
}else{//注意数组和String中的位置有一位差
if(array[i+1][j+1-1]>array[i+1-1][j+1]){
j--;
}else{
i--;
}
}
}
System.out.println("-----");
while(!result.isEmpty()){
System.out.println(result.pop()+" ");
}
}