设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为“abcbcd”,则字符串“abcb_cd”,“_a_bcbcd_”和“abcb_cd_”都是X的扩展串,这里“_”代表空格字符。 如果S1是字符串S的扩展串,T1是字符串T的扩展串,S1与T1具有相同的长度,那么我们定义字符串S1与T1的距离为相应位置上的字符的距离总和,而两个非空格字符的距离定义为它们的ASCII码的差的绝对值,而空格字符与其它任意字符之间的距离为已知的定值VAL,空格字符与空字符的距离为O。在字符串S、T的所有扩展串中,必定存在两个等长的扩展串S1、T1,使得S1与T1之间的距离达到最小,我们将这一距离定义为字符串S、T的距离。 请你写一个程序,求出字符串S、T的距离。
Input
有多组数据,每一组数据第一行为字符串S,第二行为字符串T,S、T均由小写字母组成且长度均不超过2000,第三行为一个整数VAL,1≤VAL≤100,表示空格与其它字符的距离。
Output
每组数据一行包含一个整数,表示要求的字符串S、T的距离。
Sample Input
cmc
snmn
2
Sample Output
10
方法一,递归的方法
假设S,T的扩展串S1和T1具有最小距离,那么S1[0]和T1[0]只可能有三种情况:
Case 1 Case 2 Case 3
S1[0] S[0] _ S[0]
T1[0] _ T[0] T[0]
每种情况下我们只需要求出后继子串的最小距离,再加上当前字符间的距离就能得到整个串的最小距离。因此存在一个递归的过程,可以通过递归的方法解决该问题。
递归过程可描述为:
StrDistance(S[0..SLen], T[0..TLen])= min{
VAL + StrDistance(S[1..SLEN), T[0..TLEN]),
VAL + StrDistance(S[0..SLEN], T[1..TLEN]),
abs(S[0] – T[0]) + StrDitance(S[1..SLEN], T[1..TLEN])
}
算法实现如下:
#include <math.h>
const int VAL = 10;
int StrDistance(char *S, char *T)
{
int ret, i, temp[3];
if (S[0] == ‘/0’ && T[0] == ‘/0’)
return 0;
if (S[0] == ‘/0’ && T[0] != ‘/0’)
{
for (ret = 0, i = 0; T[i] != ‘/0’; i++)
ret += VAL;
return ret;
}
if (S[0] != ‘/0’ && T[0] == ‘/0’)
{
for (ret = 0, i = 0; S[i] != ‘/0’; i++)
ret += VAL;
return ret;
}
temp[0] = StrDistance(S + 1, T) + VAL;
temp[1] = StrDistance(S, T + 1) + VAL;
temp[2] = StrDistance(S + 1, T + 1) + abs(S[0] – T[0]);
ret = min(temp[0], temp[1]);
ret = min(temp[2], ret);
return ret;
}
方法二,动态规划的方法
在利用递归方式解决这个问题的时间复杂度过高。进一步分析该问题,我们会发现有许多重复的子问题,例如:
Case 1中的后续子问题(S[1..SLen], T[0,TLen]距离)又有三种情况:
S1[1] S[1] _ S[1]
T1[1] _ T[0] T[0]
其中这三种情况对应的子问题分别为(S[2..SLen],T[0..TLen]), (S[1..SLen],T[1..TLen]), (S[2..SLen],T[1..TLen])
同理可以分析出Case 2的后续子问题子问题有(S[1..SLen],T[1..TLen]), (S[0..SLen],T[2..TLen]), (S[1..SLen],T[2..TLen])
这里(S[1..SLen],T[1..TLen])便是一个重复的子问题,递归中重复计算子问题造成了复杂都过高。使用动态规划算法,自底向上的计算
各个子问题并利用每次计算的结果,避免重复运算,从而降低算法复杂度。
用dist[i][j]存储S[0..i]和T[0..j]的距离,自底向上的计算过程可以描述为:
dist[i][j] = min{ dist[i-1][j-1] + abs(S[i) – T[j]),
dist[i-1][j] + VAL,
dist[i][j-1] + VAL }, 其中i>= 1, j >= 1.
另外 dist[0][0] = 0, dist[0][j] = dist[0][j-1] + VAL, dist[i][0] = dist[j-1][0] + VAL.
算法实现如下:
#include <math.h>
const int VAL = 10;
const int STR_MAX_LEN = 2000;
int StrDistance(char *S, char *T)
{
int i, j, temp[3];
int dist[STR_MAX_LEN][STR_MAX_LEN];
const int SLen = strlen(S);
const int TLen = strlen(T);
dist[0][0] = 0;
for (i = 1; i < SLen; i++)
dist[i][0] = dist[i – 1] + VAL;
for (i = 1; i < TLen; i++)
dist[0][i] = dist[i – 1] + VAL;
for (i = 1; i < SLen; i++)
for (j = 1; j < TLen; j++)
{
temp[0] = dist[i – 1][j – 1] + abs(S[i] – T[j]);
temp[1] = dist[i – 1][j] + VAL;
temp[2] = dist[i][j – 1] + VAL;
dist[i][j] = min(temp[0], temp[1]);
dist[i][j] = min(temp[2], dist[i][j]);
}
return dist[SLen][TLen];
}