动态规划
问题一:斐波那契数列问题:
斐波那契数列是指存在递推关系为:fib(n)=fib(n-1)+fib(n-2),且fib(0)=0,例如{0,1,1,2,3,5,8,13,…}就是一个斐波那契数列
问题:给定n,求解对应的fib(n)
- 迭代法一:
<pre>
public class LinearRecur {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(fib(i));
}
}
public static int fib(int n) {
return n > 1 ? fib(n-1)+fib(n-2) : n;
}
}
</pre>
总结:递归版的fib是十分低效的,原因是大量的递归实例被重复的调用,该迭代算法的时间复杂度为O(2^n),如下图所示。因此需要寻求一种高校的迭代策略
2. 迭代法二:
将已经计算的结果制表存储,减少了实例的重复计算,计算思路如下图
<pre>
public class LinearRecur {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(fib(i));
}
}
public static int fib(int n) {
int f1 = 1 ;
int f0 = 0;
while(n > 0) {
n--;
f1 = f1 + f0;
f0 = f1 - f0;
}
return f0;
}
}
</pre>
问题二:LCS(最长公共子序列)利用递归+分治实现
- 子序列:由序列中若干字符,按照原相对次序构成
- 最长公共子序列:两个序列的公共子序中的最长者,其中第一幅图所示不叫最长公共子序列
- 对于序列A[0,n]和序列B[0,m],LCS(A,B)存在三种情况:
a. 若n=-1或者m=-1,则取做空序列
b. 若A[n] = ‘X’=, 则取做LCS(A[0,n),B[0,M)) + ‘X’
c. 若A[n] != B[m],则在LCS(A[0,n],B[0,M))与LCS(A[0,n),B[0,M])中取更长者
整个过程可以用下图表示:
<pre>
public class LinearRecur {
public static void main(String[] args) {
int[] a = {1,2,5,6,7,9,10};
int[] b = {0,6,5,1,9,10};
int aLow = 0; int aHigh = a.length-1;
int bLow = 0; int bHigh = b.length-1;
int length = 0;
length = recurDivided(a,b,aLow,aHigh,bLow,bHigh);
System.out.println(length);
}
public static int recurDivided(int[] a, int[] b, int aLow, int aHigh, int bLow, int bHigh) {
if (aLow > aHigh || bLow > bHigh) {
return 0;
}else if (a[aHigh] == b[bHigh]) {
int length = 0;
length = recurDivided(a,b,aLow,aHigh-1,bLow,bHigh-1) + 1;
return length;
}else if (a[aHigh] != b[bHigh]){
int length1 = 0;
int length2 = 0;
length1 = recurDivided(a,b,aLow,aHigh,bLow,bHigh-1);
length2 = recurDivided(a,b,aLow,aHigh-1,bLow,bHigh);
return length1 > length2 ? length1:length2;
}
return -1; //实际不会执行
}
}
</pre>
问题二:LCS(最长公共子序列)利用迭代实现
对于该问题和斐波那契数列问题一样,利用递归+分治的思想存在许多的实例重复计算,为了降低实例的重复计算,考虑利用动态规划的思想进行迭代计算。利用递归与分治的算法,算法的时间复杂度为O(2^n),但是考虑到实际中对应于A和B的某个前缀组合O(nm)种。因此递归+分治实现并不是一个较好的算法。因此采用动态规划的算法只需要O(nm)时间即可计算出结果。下图为具体的思路:
<pre>
public class LinearRecur {
public static void main(String[] args) {
int[] b = {0,6,5,1,9,10};
int[] a = {1,2,5,6,7,9,10};
int aLength = a.length;
int bLength = b.length;
int[][] newMatrix = new int[aLength+1][bLength+1];
newMatrix = iterLcs(a,b);
for (int i = 0; i < aLength + 1; i++) {
for (int j = 0; j < bLength + 1; j++) {
System.out.printf("%d", newMatrix[i][j]);
}
System.out.println();
}
int length = 0;
System.out.printf("最长公共子序列长度为:%d", newMatrix[aLength][bLength]);
}
public static int[][] iterLcs(int[] a, int[] b) {
int[][] newMatrix = new int[a.length+1][b.length+1];
for (int i = 0; i < a.length; i++) {
boolean flag = true;
for (int j = 0; j < b.length; j++) {
if (flag && a[i] == b[j]) {
newMatrix[i+1][j+1] = newMatrix[i+1][j] > newMatrix[i][j+1] ? newMatrix[i+1][j]: newMatrix[i][j+1];
newMatrix[i+1][j+1] += 1;
flag = false;
}else {
newMatrix[i+1][j+1] = newMatrix[i+1][j] > newMatrix[i][j+1] ? newMatrix[i+1][j]: newMatrix[i][j+1];
}
}
}
return newMatrix;
}
}
</pre>