另类编辑距离

最近在学习C#,想找点东西来练练手,于是选择实现一些算法。此次选择的算法是CSDN的英雄会之前的挑战题目,遗憾的是当时我挑战失败了,于是我带着C#这把利器卷土重来。

一、题目

1、题目详情

传统的编辑距离里面有三种操作,即增、删、改,我们现在要讨论的编辑距离只允许两种操作,即增加一个字符、删除一个字符。我们求两个字符串的这种编辑距离,即把一个字符串变成另外一个字符串的最少操作次数。

输入格式:

多组数据,每组数据两行,每行一个字符串。每个字符串长度不超过1000,只有大写英文字母组成。

输出格式:

每组数据输出一行包含一个整数,表示需要最少操作的次数。


2、答题说明

输入样例:

A

ABC

BC

A

输出样例:

2

3

二、题目分析

1、疑问

  • 题目提到的传统编辑距离有三种操作:增加、删除、修改。从题目给的答案示例可以知道增加与删除的具体操作,哪么修改又包含什么?
    在C语言中使用字符串存储在字符串数组中,例如:
    char* str="ABC";
    我之前挑战用的C语言,定义的删除操作是str[i]=NULL,移动字符位置即使没交换顺序也为修改操作。因此,将"ABC"变成"AC"先执行删除操作,然后是修改操作,于是我挑战失败了。因此,题目应该是将无顺序改变的位置移动与删除合并成删除操作。 其实题目只要再补充一个示例就可以消除该疑问:
    输入样例:
    ACBC
    ABC
    输出样例:
    1
  • 题目中说有多组数据,那么所谓的多组数据是一次性输入(方案一),还是每次输入两行数据再输出结果然后继续输入两行数据(方案二)?
    疑惑主要来自于题目中给的输入与输出样例。按所示样例,应该是一次性录入所有数据,然后再输出结果。但一位经常参与这类网上编程挑战的室友告诉我,网上涉及多组测试数据都是采用的方案二。

2、分析

由于之前在C中纠结于是否将{'A',NULL,'B'}与{'A','B'}算做相同。因此此次分析中,将{'A','C','B'}->{'A',NULL,'B'}->{'A','B',NULL}定义为一次删除操作。
虽然该题目是编辑距离,但是并没有要求输出具体的操作,因此可以将该题转换为求相似度的问题。
字符串相似度:两个字符串中相同顺序(不一定相邻)的字符的最大个数,例如:"ABC"与"ACB"的相似度为2,"ABCDEF"与"ACACDEFBCD"的相似度为5。
只要算出了两个字符串的相似度,那么
编辑距离=字符串1长度-相似度+字符串2长度-相似度

三、算法流程图

四、实现代码

  • 编辑距离接口:
    using System;
    using System.Collections.Generic;
    
    namespace CSharp.Test
    {
        interface IDistance
        {
            void EditDistance(StringList desString);
        }
    }

  • 字符串列表类:
    using System;
    using System.Collections.Generic;
    
    namespace CSharp.Test
    {
        class StringList:IDistance
        {
            public StringList(string str)
            {
                stringList = new List<string>();
                if (str != null)
                {
                    for (int i = 0; i < str.Length; i++)
                    {
                        stringList.Add(str[i].ToString());
                    }
                }
            }
    
            private List<string> stringList;
    
            public int Length
            {
                get { return stringList.Count; }
            }
    
            public string this[int index]
            {
                get
                {
                    if (index < Length)
                    { 
                        return stringList[index]; 
                    }
    
                    return null;
                }
            }
    /// <summary>
    /// 编辑距离    计算只通过增加与删除操作使得源字符串变成目标字符串的最少操作数
    /// </summary>
    /// <param name="desString">目标字符串</param>
            public void EditDistance(StringList desString)
            {
                int distance;
                int h, i, j;
                int mark=0;
                int similarity = 0, tempSimilarity = 0;
                StringList srcString = this;
    
                for (h = 0; h < srcString.Length; h++)
                {
                    for (i = h; i < srcString.Length; i++)
                    {
                        for (j = mark; j < desString.Length; j++)
                        {
                            if (srcString[i] == desString[j])
                            {
                                tempSimilarity++;
                                mark = j + 1;
                                break;
                            }
                        }
                    }
    
                    mark = 0;
                    if (similarity < tempSimilarity)
                    {
                        similarity = tempSimilarity;
                    }
    
                    tempSimilarity = 0;
                }
    
                distance = srcString.Length - similarity +
                    desString.Length - similarity;
                Console.WriteLine("{0}", distance);
            }
        }
    }
    

  • 程序入口:
    using System;
    using System.Text.RegularExpressions;
    using CSharp.Test;
    
    namespace CSharp
    {
        class Program
        {
            public static int Main(string[] args)
            {
                string stringRead;
                StringList srcString=null, desString=null;
                int mark = 0;
                while ((stringRead = Console.ReadLine()) !="EOF")
                {
                    Regex reg=new Regex("[A-Z]");
                    if (reg.IsMatch(stringRead))
                    {
                        if (mark % 2 == 0)
                        {
                            srcString = new StringList(stringRead);
                            mark=1;
                        }
                        else
                        {
                            desString = new StringList(stringRead);
                            srcString.EditDistance(desString);
                            mark = 0;
                        }
                    }
                    else
                    {
                        srcString = null;
                        desString = null;
                        mark = 0;
                    }
                }
    
                return 0;
            }
        }
    }
    

由于在写代码的时候没有考虑不需要实际改变字符串,所以用的一个存储字符串列表来存储获取的输入(其实用SringBuilder就可以了的,但对C#还不是很熟悉,所以当时没想到)。

五、结果展示

你可能感兴趣的:(C#)