这道题目题意很清晰,也很容易想到一个O(n2)的算法,但是n有25000, O(n2)算法会超时。
我的同学曾跟我说过O(n*logn*2*26*16)的算法,之前一直没做,今天在多次WA之后,终于AC了。
我们这样考虑:一个单词(假设长度为16)由其他的单词经过删除,添加,替换一个字母得到,反过来,我们可以由这个单词经过相反的操作得到其他单词,效果是的等价的。设f[i]表示以第i个单词结尾的最长的编辑距离,则我们对第i个单词做16(单词的长度)次删除操作,16*26次添加操作,16*26次替换操作,从第0个到第i-1个单词中二分查找匹配的单词,若匹配,则更新,这样复杂度就降下来了。但效率还是不太高。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 25010; char s[MAXN][20]; int f[MAXN]; int binary(int l, int r, char *_s) { int m, t; while(l < r){ m = l + (r - l) / 2; if(!(t = strcmp(_s, s[m]))){ return m; }else if(t > 0){ l = m + 1; }else r = m; } if(!strcmp(_s, s[m])) return m; return -1; } int main() { //freopen("input.txt", "r", stdin); int n = 0, len, ans; char t[20]; while(scanf("%s", s[n]) == 1) n++; int p; memset(f, 0, sizeof(f)); ans = f[0] = 1; for(int i = 1; i < n; i++){ f[i] = 1; len = strlen(s[i]); for(int k = len - 1; k >= 0; k--){ //删除 strcpy(t, s[i]); for(int j = k; j < len; j++) t[j] = t[j + 1]; p = binary(0, i, t); if(p != -1 && f[i] < f[p] + 1) f[i] = f[p] + 1; } for(int k = len; k >= 0; k--){//添加 strcpy(t, s[i]); for(int j = len; j >= k; j--){ t[j + 1] = t[j]; } int up; if(k == len) up = 25; else up = s[i][k] - 'a'; for(int j = 0; j <= up; j++){ t[k] = j + 'a'; p = binary(0, i, t); if(p != -1 && f[i] < f[p] + 1) f[i] = f[p] + 1; } } for(int k = len - 1; k >= 0; k--){ //替换 strcpy(t, s[i]); for(int j = 0; j < s[i][k] - 'a'; j++){ t[k] = j + 'a'; p = binary(0, i, t); if(p != -1 && f[i] < f[p] + 1) f[i] = f[p] + 1; } } if(ans < f[i]) ans = f[i]; } printf("%d\n", ans); return 0; }