Leetcode Edit Distance,本题可以使用两种法方来完成,不过可能效率有所不一样。
动态规化
使用record[word1.length + 1][word2.length + 1] 记录值。
如果要计算word1[index1…end1], word2[index2…end2]的值,可以分成以下四种情况:
1. 如果word1[index1] == word2[index2],最优值为record[index1+1][index2+1]
2. 替换word1[index1]为word2[index2],此时最优值为record[index1 + 1][index2 + 1] + 1
3. 删除word1[index2],此时最优值为record[index1 + 1][index2] + 1
4. 在word1中插入一个与word2[index2]相等的值,此时最优值为record[index1][index2 + 1] + 1
相关代码如下:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
/**
* Using the dynamic programming algorithm.
* Using a table record[len1 + 1][len2 + 2] to record the tmp result
* and the record[0][0] will be the result
*/
class Solution {
public:
int minDistance(string word1, string word2) {
int len1 = word1.length();
int len2 = word2.length();
int minNum = len1 > len2? len1: len2;;
int curNum = 0;
vector<vector<int> > record = vector<vector<int> >(len1 + 1, vector<int>(len2 + 1, -1));
recursiveMin(word1, 0, word2, 0, record);
return record[0][0];
}
void recursiveMin(string& from, int fromIdx, string& to, int toIdx,
vector<vector<int> >& record) {
// if there is a record just return
if (record[fromIdx][toIdx] != -1) {
return;
}
// till the end of this turn, calculate the value and return
if (fromIdx == from.length() || toIdx == to.length()) {
record[fromIdx][toIdx] = (from.length() - fromIdx) + (to.length() - toIdx);
return;
}
if (from[fromIdx] == to[toIdx]) {
// this must be the optimal
recursiveMin(from, fromIdx + 1, to, toIdx + 1, record);
record[fromIdx][toIdx] = record[fromIdx + 1][toIdx + 1];
} else {
recursiveMin(from, fromIdx + 1, to, toIdx + 1, record);
recursiveMin(from, fromIdx, to, toIdx + 1, record);
recursiveMin(from, fromIdx + 1, to, toIdx, record);
// get the minest of the three
record[fromIdx][toIdx] = minOfThree(
record[fromIdx + 1][toIdx + 1],
record[fromIdx][toIdx + 1],
record[fromIdx + 1][toIdx]
) + 1;
}
}
int minOfThree(int a, int b, int c) {
if (a > b) {
return b < c? b : c;
} else {
return a < c? a : c;
}
}
};
int main(int argc, char* argv[]) {
Solution so;
cout<<"result: "<<so.minDistance(string(argv[1]), string(argv[2]))<<endl;
return 0;
}
测试:
time ./a.out pneumonoultramicroscopicsilicovolcanoconiosis ultramicroscopically
result: 27
real 0m0.004s
user 0m0.001s
sys 0m0.002s
分支界限法
分支界限法主要情况与动态规划相似,主要不同的是,其不使用record数组来记录情况,而是记录一个当前最小值min,以及当前值cur,以及当前情况进行预估.
针对本问题的预估值为:word1和word2剩余长度较大者加上cur
。并使用预估值做为剪支条件。
相关代码如下:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
/**
* Using branch-bound method
* Each turn we get a espect max result, if the result greater than the current
* result, just cut this branch
*/
class Solution {
public:
int minDistance(string word1, string word2) {
int len1 = word1.length();
int len2 = word2.length();
int minNum = len1 > len2? len1: len2;;
int curNum = 0;
recursiveMin(word1, 0, word2, 0, 0, minNum, len1, len2);
return minNum;
}
void recursiveMin(string& from, int fromIdx, string& to, int toIdx,
int curNum, int& minNum, int len1, int len2) {
// leverage this branch
if (curNum + (len1 - len2) >= minNum || curNum + (len2 - len1) > minNum) {
return;
}
// an end
if (fromIdx == from.length() || toIdx == to.length()) {
curNum = curNum + (from.length() - fromIdx) + (to.length() - toIdx);
minNum = curNum < minNum? curNum : minNum;
return;
}
// get other condition
if (from[fromIdx] == to[toIdx]) {
recursiveMin(from, fromIdx + 1, to, toIdx + 1, curNum, minNum,
len1 - 1, len2 - 1);
} else {
recursiveMin(from, fromIdx + 1, to, toIdx + 1, curNum + 1, minNum,
len1 - 1, len2 - 1);
recursiveMin(from, fromIdx, to, toIdx + 1, curNum + 1, minNum, len1, len2 - 1);
recursiveMin(from, fromIdx + 1, to, toIdx, curNum + 1, minNum, len1 - 1, len2);
}
}
};
int main(int argc, char* argv[]) {
Solution so;
cout<<"result: "<<so.minDistance(string(argv[1]), string(argv[2]))<<endl;
return 0;
}
测试:
time ./a.out pneumonoultramicroscopicsilicovolcanoconiosis ultramicroscopically
result: 27
real 0m0.007s
user 0m0.004s
sys 0m0.002s
总结
从以上运行情况也可以看出,动态规划的性能好于分支界限法,这与我在leetcode测试基本一致,动态规划为:24ms,分支界限法为:84ms。