3 abcdefg abcdef ab ab mnklj jlknm
1 0 4
这道题的时间限制是1秒,但处理的字符串长度可能达到1000,所以如果使用递归的话,则必然超时。因此,可采用动态规划的方法,构造一个二维数组,数组的“长”和“宽”分别是两个字符串的长度。
以题中的一个例子举例,字符串a=“jlknm”,b=“mnklj”,则可构造一个6×6的二维数组array,并将二维数组的第一行和第一列初始化为如下,因为一个空字符串和任意一个字符串的距离始终为该字符串的长度。
用两层for循环遍历两个字符串a、b(i和j从1开始取值),对比每一个字符a[i-1]和b[j-1],若两个字符相等,即a[i-1] == b[j-1],则不增加距离,因此对应的数组array[i][j]=array[i-1][j-1];若两个字符不相等,则可删除a[i-1]这个字符、删除b[j-1]这个字符,或修改a[i-1]使它与b[i-1]相等。array[i][j]取这三种方法的最小值。选择修改,则array[i][j] = 1 + array[i-1][j-1],若选择删除a[i-1],则array[i][j] = 1 + array[i-1][j],若选择删除b[i-1],则array[i][j] = 1 + array[i][j-1]。运用这个方法,可将二维数组填满,如下图所示。
最后,取这个数组的最后一个元素4,即为答案。
最终AC的代码如下:
#include
#include
using namespace std;
int m_min(int a, int b, int c){
if (a <= b && a <= c)
return a;
else if (b <= a && b <= c)
return b;
else
return c;
}
int count_distance(string a, string b){
int na = a.size();
int nb = b.size();
// 分配二维数组
int **array = new int*[na + 1];
for (int i = 0; i <= na; ++i){
array[i] = new int[nb + 1];
}
// 初始化二维数组的第一行和第一列
for (int i = 0; i <= nb; ++i){
array[0][i] = i;
}
for (int i = 0; i <= na; ++i){
array[i][0] = i;
}
for (int i = 1; i <= na; ++i){
for (int j = 1; j <= nb; ++j){
if (a[i - 1] == b[j - 1])
array[i][j] = array[i-1][j-1];
else
array[i][j] = m_min(1 + array[i-1][j-1], 1 + array[i-1][j], 1 + array[i][j-1]);
}
}
int m_distance = array[na][nb];
// 释放二维数组
for (int i = 0; i <= na; ++i){
delete[] array[i];
}
delete[] array;
return m_distance;
}
int main(){
int n = 0;
string a, b;
cin >> n;
while(n--){
cin >> a >> b;
cout << count_distance(a, b) << endl;
}
}
----------------------------------------------------------------------分割线----------------------------------------------------------------------------
附上错误经历,以提醒自己。
下面这个解法思路比较清晰,但是超时。。
#include
#include
using namespace std;
int count_distance(string a, string b){
if (a == "")
return b.size();
if (b == "")
return a.size();
if (a[0] == b[0])
return count_distance(string(a.begin()+1, a.end()), string(b.begin()+1, b.end()));
return min(1 + count_distance(string(a.begin()+1, a.end()), string(b.begin()+1, b.end())),// 修改
min(1 + count_distance(a, string(b.begin()+1, b.end())), 1 + count_distance(string(a.begin()+1, a.end()), b))); // 删除
}
int main(){
int n = 0;
string a, b;
cin >> n;
while(n--){
cin >> a >> b;
cout << count_distance(a, b) << endl;
}
}
#include
#include
using namespace std;
int m_distance;
int count_distance(string a, string b, int distance){
if (distance >= m_distance)
return m_distance;
// 若两个子串相等,则不再增加距离
if (a == b){
m_distance = distance;
return distance;
}
// 两个字符串长度相等,则应修改位置
if (a.size() == b.size()){
for (string::size_type i = 0; i < a.size(); ++i){
if (a[i] != b[i])
++distance;
}
if (distance < m_distance)
m_distance = distance;
return distance;
}
// 删除一个字符,字符位置是i
for (string::size_type i = 0; i < a.size(); ++i){
if (distance + 1 >= m_distance)
return m_distance;
string temp_a = a.substr(0, i) + a.substr(i+1);
count_distance(temp_a, b, distance + 1);
}
}
int main(){
int n = 0;
string a, b;
cin >> n;
while(n--){
m_distance = 1001;
cin >> a >> b;
a.size() >= b.size() ? count_distance(a, b, 0) : count_distance(b, a, 0);
cout << m_distance << endl;
}
}