字串編輯距離 經典 dp
阿新 • • 發佈:2019-02-09
可以參考這個部落格:點選開啟連結
比較兩個字串相似度,可以通過最長公共子串,或者最長公共子序列,還有就是編輯距離。兩個字串通過插入,刪除或者修改,來達到一致,編輯距離越短,可知相似度越高。
因為當前字串肯定是根據長度 -1 的字串演變而來,從上面的 dp 也可以看出,i 只和 i-1 有關,所以為了節省空間,可以採用滾動陣列。時間複雜度不變,但是空間複雜度從 O(n*m) 降到O( 2*max( n , m ) ) 。#include <bits/stdc++.h> using namespace std ; #define Min( a , b , c ) ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) ) int dp[1010][1010] ; char s1[1010] , s2[1010] ; int main(){ int n , m , i , j , cost ; while( ~scanf("%s%s" , s1 , s2 ) ){ n = (int)strlen( s1 ) ; m = (int)strlen( s2 ) ; for( i = 0 ; i <= n ; ++i ) dp[i][0] = i ; // 另一個字串長度為 0 時,長度就是本字串當前長度 for( i = 0 ; i <= m ; ++i ) dp[0][i] = i ; for( i = 1 ; i <= n ; ++i ) for( j = 1 ; j <= m ; ++j ){ cost = s1[i-1] == s2[j-1] ? 0 : 1 ; // 當前字元相等,可以選擇修改 + cost dp[i][j] = Min( dp[i-1][j]+1 , dp[i][j-1]+1 , dp[i-1][j-1]+cost ) ; } cout << dp[n][m] << endl ; } return 0 ; }
上面的部落格中還有一種空間複雜度 O( max( n , m ) ) 的解法, 利用了當前字元匹配相等,不需要做任何操作這一特點。#include <bits/stdc++.h> using namespace std ; #define Min( a , b , c ) ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) ) int dp[2][1010] ; char s1[1010] , s2[1010] ; int main(){ int n , m , i , j , cost ; while( ~scanf("%s%s" , s1 , s2 ) ){ n = (int)strlen( s1 ) ; m = (int)strlen( s2 ) ; memset( dp , 0 , sizeof( dp ) ) ; for( i = 0 ; i <= m ; ++i ) dp[0][i] = i ; for( i = 1 ; i <= n ; ++i ){ dp[i&1][0] = i ; for( j = 1 ; j <= m ; ++j ){ cost = s1[i-1] == s2[j-1] ? 0 : 1 ; dp[i&1][j] = Min( dp[(i-1)&1][j]+1 , dp[i&1][j-1]+1 , dp[(i-1)&1][j-1]+cost ) ; } } cout << dp[n&1][m] << endl ; } return 0 ; }
#include <bits/stdc++.h> using namespace std ; #define Min( a , b , c ) ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) ) int dp[1010] ; char s1[1010] , s2[1010] ; int main(){ int n , m , i , j , temp , cur ; while( ~scanf("%s%s" , s1 , s2 ) ){ cout << "s1 = " << s1 << "\ts2 = " << s2 << endl ; n = (int)strlen( s1 ) ; m = (int)strlen( s2 ) ; for( i = 0 ; i <= m ; ++i ) dp[i] = i ; for( i = 1 ; i <= n ; ++i ){ cur = i-1 ; // 因為另一個字串長度不為 0 , 初始編輯距離-1,對應二維的 dp[i-1] for( j = 1 ; j <= m ; ++j ){ temp = dp[j] ; dp[j] = s1[i-1] == s2[j-1] ? cur : 1 + Min( dp[j-1] , dp[j] , cur ) ; cur = temp ; // 儲存下次的 dp[i-1][j-1] ; } } cout << dp[m] << endl ; } return 0 ; }