• 求2个字符串的最短编辑距离 java 实现


    EditStepInfo.java:
    1. import lombok.Getter;
    2. import lombok.Setter;
    3. import java.io.Serializable;
    4. import java.util.List;
    5. @Getter
    6. @Setter
    7. public class EditStepInfo implements Serializable {
    8. private String str1;
    9. private String str2;
    10. // str1和 str2 的最短编辑路基
    11. private int sed;
    12. private List steps;
    13. private String tempString;
    14. }

    StepVO.java:
    1. import lombok.Getter;
    2. import lombok.Setter;
    3. import java.io.Serializable;
    4. @Getter
    5. @Setter
    6. public class StepVO implements Serializable {
    7. public static final String OPT_TYPE_ADD = "add";
    8. public static final String OPT_TYPE_DELETE = "delete";
    9. public static final String OPT_TYPE_UPDATE = "UPDATE";
    10. /**
    11. * 当前变换描述
    12. */
    13. private String desc;
    14. private int optIndex;
    15. private Character optChar1;
    16. private Character optChar2;
    17. private String optType;
    18. /**
    19. * 当前变换成的字符串
    20. */
    21. private String tempString;
    22. public static void main(String[] args) {
    23. String s = "abcdf";
    24. Character c = s.charAt(0);
    25. System.out.println( c.toString() );
    26. }
    27. }

    ShortestEditDistanceTest.java:
    1. import java.util.ArrayList;
    2. import java.util.List;
    3. public class ShortestEditDistanceTest {
    4. private static EditStepInfo[][] MAT_SED = null;
    5. public static void main(String[] args) {
    6. // m o t h e r
    7. // m o n s t e r
    8. String string1 = "calculate";
    9. String string2 = "caketakes";
    10. MAT_SED = new EditStepInfo[ string1.length() ][ string2.length() ];
    11. calculateShortestEditDistance(string1, string2);
    12. for( int i=0;i
    13. for (int j = 0; j < string2.length(); j++) {
    14. EditStepInfo editStepInfo = MAT_SED[i][j];
    15. printEditStepInfo( editStepInfo );
    16. System.out.println();
    17. System.out.println();
    18. }
    19. }
    20. }
    21. private static void printEditStepInfo(EditStepInfo editStepInfo) {
    22. System.out.println( editStepInfo.getStr1() + " 到 " + editStepInfo.getStr2() + " 的最小编辑距离:" + editStepInfo.getSed() );
    23. System.out.println( "编辑步骤:" );
    24. List steps = editStepInfo.getSteps();
    25. if( steps == null || steps.size() == 0 ){
    26. System.out.println( "\ttempString = " + editStepInfo.getTempString() );
    27. }else {
    28. String tempString = editStepInfo.getStr1();
    29. for( StepVO step:steps ){
    30. String optType = step.getOptType();
    31. int optIndex = step.getOptIndex();
    32. Character optChar1 = step.getOptChar1();
    33. if( StepVO.OPT_TYPE_ADD.equals( optType ) ){
    34. // 新增
    35. // 0 1 2 3 4
    36. tempString = addChar2String( tempString,optChar1,optIndex );
    37. }else if( StepVO.OPT_TYPE_DELETE.equals( optType ) ){
    38. // 删除
    39. // tempString = removeCharacter( tempString,optIndex );
    40. tempString = updateCharacterInString( tempString,optIndex,' ' );
    41. }else if( StepVO.OPT_TYPE_UPDATE.equals( optType ) ){
    42. // 修改
    43. Character optChar2 = step.getOptChar2();
    44. tempString = updateCharacterInString( tempString,optIndex,optChar2 );
    45. }
    46. System.out.println( "\t" + step.getDesc() + ":" + tempString + " optIndex = " + optIndex);
    47. }
    48. }
    49. }
    50. private static String updateCharacterInString(String str, int updateIndex, Character character) {
    51. // 01234
    52. if( updateIndex < 0 ){
    53. updateIndex = 0;
    54. }else if( updateIndex >= str.length() ){
    55. updateIndex = str.length() - 1;
    56. }
    57. int length = str.length();
    58. String str_result = "";
    59. for( int i=0;i
    60. char c = str.charAt(i);
    61. if( i == updateIndex ){
    62. str_result += character;
    63. }else {
    64. str_result += c;
    65. }
    66. }
    67. return str_result;
    68. }
    69. private static String removeCharacter(String str,int removeIndex) {
    70. // 01234
    71. if( removeIndex < 0 ){
    72. removeIndex = 0;
    73. }
    74. if( removeIndex >= str.length() ){
    75. removeIndex = str.length() - 1;
    76. }
    77. if( removeIndex == 0 ){
    78. return str.substring( 1 );
    79. }else if( removeIndex == str.length() - 1 ){
    80. return str.substring( 0,removeIndex );
    81. }else {
    82. return str.substring( 0,removeIndex ) + str.substring( removeIndex + 1 );
    83. }
    84. }
    85. private static String addChar2String(String str,Character character, int addIndex) {
    86. if( addIndex > str.length() ){
    87. addIndex = str.length();
    88. }
    89. return str.substring( 0,addIndex ) + character + str.substring( addIndex );
    90. }
    91. private static EditStepInfo calculateShortestEditDistance( String string1,String string2 ){
    92. if( string1 == null || string1.length() == 0 ){
    93. EditStepInfo editStepInfo = new EditStepInfo();
    94. editStepInfo.setStr1( string1 );
    95. editStepInfo.setStr2( string2 );
    96. editStepInfo.setSed( string2.length() );
    97. return editStepInfo;
    98. }
    99. if( string2 == null || string2.length() == 0){
    100. EditStepInfo editStepInfo = new EditStepInfo();
    101. editStepInfo.setStr1( string1 );
    102. editStepInfo.setStr2( string2 );
    103. editStepInfo.setSed( string1.length() );
    104. return editStepInfo;
    105. }
    106. int len1 = string1.length();
    107. int len2 = string2.length();
    108. for( int i=0;i
    109. String str1 = string1.substring(0, i + 1);
    110. for( int j=0;j
    111. String str2 = string2.substring(0, j + 1);
    112. EditStepInfo editStepInfo = new EditStepInfo();
    113. editStepInfo.setStr1( str1 );
    114. editStepInfo.setStr2( str2 );
    115. if( str1.length() == 1 ){
    116. if( str2.length() == 1 ){
    117. if( str1.equals( str2 ) ){
    118. // str1 和 str2 的长度均为1,并且 str1 和 str2 相等
    119. // a
    120. // a
    121. List steps = new ArrayList<>();
    122. editStepInfo.setSteps( steps );
    123. editStepInfo.setTempString( str1 );
    124. editStepInfo.setSed( steps.size() );
    125. }else {
    126. // str1 和 str2 的长度均为1,并且 str1 和 str2 不相等
    127. // a
    128. // b
    129. List steps = new ArrayList<>();
    130. StepVO step = new StepVO();
    131. step.setDesc( "将 " + str1 + " 修改为 " + str2 );
    132. step.setTempString( str2 );
    133. step.setOptType( StepVO.OPT_TYPE_UPDATE );
    134. step.setOptChar1( str1.charAt( 0 ) );
    135. step.setOptIndex( 0 );
    136. step.setOptChar2( str2.charAt( 0 ) );
    137. steps.add( step );
    138. editStepInfo.setSteps( steps );
    139. editStepInfo.setTempString( getLastTempString( steps ) );
    140. editStepInfo.setSed( steps.size() );
    141. }
    142. }else {
    143. if( str2.contains( str1 ) ){
    144. // str1 的长度为1,str2 的长度大于1,并且 str1 在 str2 中出现
    145. // a
    146. // ..a...
    147. // 组装编辑步骤信息
    148. List steps = buildEditSteps( str1.charAt(0),str2 );
    149. editStepInfo.setSteps( steps );
    150. editStepInfo.setTempString( getLastTempString( steps ) );
    151. editStepInfo.setSed( steps.size() );
    152. }else {
    153. // str1 的长度为1,str2的长度大于1,并且str1在 str2中不存在
    154. // a
    155. // ..b...
    156. // 组装编辑步骤信息
    157. List steps = buildEditSteps(str1.charAt(0), str2);
    158. editStepInfo.setSteps( steps );
    159. editStepInfo.setTempString( getLastTempString( steps ) );
    160. editStepInfo.setSed( steps.size() );
    161. }
    162. }
    163. }else {
    164. if( str2.length() == 1 ){
    165. if( str1.contains( str2 ) ){
    166. // ...a..
    167. // a
    168. // 组装编辑步骤信息
    169. List steps = buildEditSteps(str1, str2.charAt(0));
    170. editStepInfo.setSteps( steps );
    171. editStepInfo.setTempString( getLastTempString( steps ) );
    172. editStepInfo.setSed( steps.size() );
    173. }else {
    174. // ...b..
    175. // a
    176. // 组装编辑步骤信息
    177. List steps = buildEditSteps(str1, str2.charAt(0));
    178. editStepInfo.setSteps( steps );
    179. editStepInfo.setTempString( getLastTempString( steps ) );
    180. editStepInfo.setSed( steps.size() );
    181. }
    182. }else {
    183. Character lastChar1 = getLastChar(str1);
    184. Character lastChar2 = getLastChar(str2);
    185. if( lastChar1.equals( lastChar2 ) ){
    186. // ------a
    187. // ---------a
    188. // 组装编辑步骤信息
    189. EditStepInfo editStepInfo_prev = MAT_SED[i - 1][j - 1];
    190. List steps = new ArrayList<>();
    191. List steps_prev = editStepInfo_prev.getSteps();
    192. String tempString = editStepInfo_prev.getTempString() + lastChar1;
    193. if( steps_prev != null ){
    194. steps.addAll( steps_prev );
    195. }
    196. editStepInfo.setSteps( steps );
    197. editStepInfo.setTempString( tempString );
    198. editStepInfo.setSed( steps.size() );
    199. }else {
    200. // ----- a
    201. // ........ b
    202. // 1. str1 的 "-----" 部分转换为 str2,再删除 a
    203. // 2. str1 转换为 str2 的 "........" 部分,再添加 b
    204. // 3. str1 的 "-----" 部分转换为 str2 的 "........" 部分,再将a修改为 b
    205. // 求 方法1、2、3中选一个最小的编辑步骤作为最终的编辑步骤
    206. EditStepInfo editStepInfo_prev_1 = MAT_SED[i - 1][j];
    207. EditStepInfo editStepInfo_prev_2 = MAT_SED[i][j - 1];
    208. EditStepInfo editStepInfo_prev_3 = MAT_SED[i - 1][j - 1];
    209. EditStepInfo editStepInfo_prev_min = editStepInfo_prev_1;
    210. int minMethodNum = 1;
    211. if( editStepInfo_prev_2.getSed() < editStepInfo_prev_min.getSed() ){
    212. editStepInfo_prev_min = editStepInfo_prev_2;
    213. minMethodNum = 2;
    214. }
    215. if( editStepInfo_prev_3.getSed() < editStepInfo_prev_min.getSed() ){
    216. editStepInfo_prev_min = editStepInfo_prev_3;
    217. minMethodNum = 3;
    218. }
    219. List steps = new ArrayList<>();
    220. List steps_prev_min = editStepInfo_prev_min.getSteps();
    221. if( steps_prev_min != null ){
    222. steps.addAll( steps_prev_min );
    223. }
    224. StepVO step_last = null;
    225. if( steps.size() > 0 ){
    226. step_last = steps.get(steps.size() - 1);
    227. }
    228. String tempString = editStepInfo_prev_min.getTempString();
    229. StepVO step = new StepVO();
    230. if( minMethodNum == 1 ){
    231. step.setDesc( "删除 " + lastChar1 );
    232. step.setOptType( StepVO.OPT_TYPE_DELETE );
    233. step.setOptChar1( lastChar1 );
    234. step.setOptIndex( str1.length() - 1 );
    235. // todo 估计有问题???
    236. step.setTempString( tempString );
    237. }else if( minMethodNum == 2 ){
    238. step.setDesc( "添加 " + lastChar2 );
    239. step.setOptType( StepVO.OPT_TYPE_ADD );
    240. step.setOptChar1( lastChar2 );
    241. if( step_last != null ){
    242. step.setOptIndex( step_last.getOptIndex() + 1 );
    243. }else {
    244. step.setOptIndex( str1.length() );
    245. }
    246. // todo 估计有问题???
    247. step.setTempString( tempString + lastChar2 );
    248. }else if( minMethodNum == 3 ){
    249. step.setDesc( "修改 " + lastChar1 + " 为 " + lastChar2 );
    250. step.setOptType( StepVO.OPT_TYPE_UPDATE );
    251. step.setOptChar1( lastChar1 );
    252. step.setOptChar2( lastChar2 );
    253. step.setOptIndex( str1.length() - 1 );
    254. // todo 估计有问题???
    255. step.setTempString( tempString + lastChar2 );
    256. }
    257. steps.add( step );
    258. editStepInfo.setSteps( steps );
    259. editStepInfo.setTempString( tempString );
    260. editStepInfo.setSed( steps.size() );
    261. }
    262. }
    263. }
    264. MAT_SED[ i ][ j ] = editStepInfo;
    265. }
    266. }
    267. return MAT_SED[ string1.length() - 1 ][ string2.length() - 1 ];
    268. }
    269. private static String getLastTempString(List steps) {
    270. if( steps == null || steps.size() == 0 ){
    271. return null;
    272. }
    273. return steps.get( steps.size() - 1 ).getTempString();
    274. }
    275. /**
    276. * 组装将字符 srcChar 转换成字符串 targetString 的编辑步骤
    277. * @param srcChar 例如:a
    278. * @param targetString 例如:bcdefg
    279. * @return
    280. */
    281. private static List buildEditSteps(Character srcChar, String targetString) {
    282. boolean hasMeet = false;
    283. int length = targetString.length();
    284. List steps = new ArrayList<>();
    285. for( int i = 0;i < length;i++ ){
    286. Character char2 = targetString.charAt( i );
    287. if( hasMeet ){
    288. StepVO step = new StepVO();
    289. step.setDesc( "添加 " + char2 );
    290. step.setOptChar1( char2 );
    291. step.setOptIndex( i );
    292. step.setOptType( StepVO.OPT_TYPE_ADD );
    293. steps.add( step );
    294. }else {
    295. if( srcChar.equals( char2 ) ){
    296. // do nothing
    297. hasMeet = true;
    298. }else {
    299. StepVO step = new StepVO();
    300. step.setDesc( "添加 " + char2 );
    301. step.setOptChar1( char2 );
    302. step.setOptIndex( i );
    303. step.setOptType( StepVO.OPT_TYPE_ADD );
    304. steps.add( step );
    305. }
    306. }
    307. }
    308. if( !hasMeet ){
    309. // 此种情况只发生在 targetString 中不包含 srcChar 时
    310. StepVO step = new StepVO();
    311. step.setDesc( "删除 " + srcChar );
    312. step.setOptChar1( srcChar );
    313. step.setOptIndex( 0 );
    314. step.setOptType( StepVO.OPT_TYPE_DELETE );
    315. steps.add( 0,step );
    316. }
    317. // 设置 每个步骤生成的 tempString
    318. String tempString = String.valueOf( srcChar );
    319. for( StepVO step:steps ){
    320. String optType = step.getOptType();
    321. Character optChar1 = step.getOptChar1();
    322. if( StepVO.OPT_TYPE_DELETE.equals( optType ) ){
    323. tempString = tempString.replaceFirst( optChar1.toString(),"" );
    324. }else if( StepVO.OPT_TYPE_ADD.equals( optType ) ){
    325. tempString += optChar1;
    326. }
    327. step.setTempString( tempString );
    328. }
    329. return steps;
    330. }
    331. private static List buildEditSteps(String srcString, Character targetChar) {
    332. // abcdefg
    333. // c
    334. boolean hasMeet = false;
    335. int length = srcString.length();
    336. List steps = new ArrayList<>();
    337. for( int i = 0;i < length;i++ ){
    338. Character char1 = srcString.charAt( i );
    339. if( hasMeet ){
    340. StepVO step = new StepVO();
    341. step.setDesc( "删除 " + char1 );
    342. step.setOptChar1( char1 );
    343. step.setOptIndex( i );
    344. step.setOptType( StepVO.OPT_TYPE_DELETE );
    345. steps.add( step );
    346. }else {
    347. if( targetChar.equals( char1 ) ){
    348. // do nothing
    349. hasMeet =true;
    350. }else {
    351. StepVO step = new StepVO();
    352. step.setDesc( "删除 " + char1 );
    353. step.setOptChar1( char1 );
    354. step.setOptIndex( i );
    355. step.setOptType( StepVO.OPT_TYPE_DELETE );
    356. steps.add( step );
    357. }
    358. }
    359. }
    360. if( !hasMeet ){
    361. StepVO step = new StepVO();
    362. step.setDesc( "添加 " + targetChar );
    363. step.setOptChar1( targetChar );
    364. step.setOptIndex( 0 );
    365. step.setOptType( StepVO.OPT_TYPE_ADD );
    366. steps.add( 0,step );
    367. }
    368. String tempString = srcString;
    369. for( StepVO step:steps ){
    370. String optType = step.getOptType();
    371. Character optChar1 = step.getOptChar1();
    372. if( StepVO.OPT_TYPE_ADD.equals( optType ) ){
    373. tempString += optChar1;
    374. }else if( StepVO.OPT_TYPE_DELETE.equals( optType ) ){
    375. tempString = tempString.replaceFirst( optChar1.toString(),"" );
    376. }
    377. step.setTempString( tempString );
    378. }
    379. return steps;
    380. }
    381. private static Character getLastChar(String str) {
    382. if( str == null || str.length() == 0 ){
    383. return null;
    384. }
    385. return str.charAt(str.length() - 1);
    386. }
    387. }

    1. mother
    2. monster
    3. 最小编辑距离:3
    4. 编辑步骤:
    5. 添加 n
    6. 添加 s
    7. 删除 h

  • 相关阅读:
    服装PLM解决方案能带给企业什么?
    网络安全:MSF常用命令总结
    mysql-MVCC
    【前端工程化】使用jest单元测试,提高效率的方法
    自定义注解和@Target、@Retention注解的使用
    开题报告不知道怎么写?
    webpack拓展篇(六十八):bundle 和 bundless 的差异
    计算机系统(23)--- 死锁的处理策略
    Linux下安装MySQL
    Pinely Round 1 (Div. 1 + Div. 2) E - Make It Connected思维&&分类讨论
  • 原文地址:https://blog.csdn.net/heshiyuan1406146854/article/details/134272488