题目
给出两个数组A,B,a可以通过增、删、改任意位置的操作去变成b,现在需要使用dp计算出a变为b的最少步数。
例如:A[0, 1, 2, 3, 4] → B[0, 1, 3, 5] 需要两个操作。
解法
首先根据例子,制作出一个对应的表,如下:
null | 0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|---|
null | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 1 | 0 | 1 | 2 | 3 | 4 |
1 | 2 | 1 | 0 | 1 | 2 | 3 |
3 | 3 | 2 | 1 | 1 | 1 | 2 |
5 | 4 | 3 | 2 | 2 | 2 | 2 |
首先需要对矩阵的第0行和第0列进行初始化。
然后找出状态方程:
从图中可以看出如果A[i - 1] == B[j - 1], C[i][j] = C[i -1][j -1]
除此以外,C[i][j] = 1 + min(C[i - 1][j],C[i][j -1],C[i - 1][j - 1])
这三个状态代表,增,删,改三个状态,如果A[i - 1] != B[j -1]的话,最少步数已经是1,然后加上前面状态的最少步数就是当前格子的最少步数。
或者可以这样想,在找到相同数字之前,做了什么操作,如下图所示:
(经过和同学讨论,实际上这题也可以想象为最短路径的题,就是这个当前格子可以通过左边格子,上边格子还有斜上方格子三个位置到达,然后我们只需要算得最短路径,就是问题的解)
用java代码实现过程如下:
package Test;
import java.util.*;
import java.util.StringTokenizer;
public class Test{
public static void main(String[] args) {
int[] a = {0,1,3,5};
int[] b = {0,1,2,3,4};
int[][] c = new int[a.length + 1][b.length + 1];
c[0][0] = 0;
//这里可以写进下面的循环里面
for(int i = 1;i < a.length + 1;i++) {
c[i][0] = c[i - 1][0] + 1;
}
for(int i = 1;i < b.length + 1;i++) {
c[0][i] = c[0][i - 1] + 1;
}
for(int i = 1;i < a.length + 1;i++) {
for(int j = 1;j < b.length + 1;j++) {
if(a[i - 1] == b[j - 1]) {
c[i][j] = c[i - 1][j - 1];
}
else {
c[i][j] = 1 + Math.min(c[i - 1][j],Math.min(c[i - 1][j - 1],c[i][j - 1]));
}
}
}
for(int i = 0;i < a.length + 1;i++) {
for(int j = 0;j < b.length + 1;j++) {
System.out.print(c[i][j] + " ");
}
System.out.println();
}
}
}