走在架構師的大道上 Jack.Wang's home

          Java, C++, linux c, C#.net 技術,軟件架構,領域建模,IT 項目管理 Dict.CN 在線詞典, 英語學習, 在線翻譯

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            195 Posts :: 3 Stories :: 728 Comments :: 0 Trackbacks
           

          計算字符串相似度的簡易算法

          算法設計背景:

          最近設計知識管理系統的資源導入功能,為了盡量的做到組件化,方便擴展,方便其他模塊使用。簡化組件提供的和需要的接口,設計并實現了基于 Mapping 機制的導入框架。其中有一功能用到了計算兩個字符串相似度的算法,簡單設計如下以便參考:

          設計思想:

             把兩個字符串變成相同的基本操作定義如下:

          1.     修改一個字符(如把 a 變成 b

          2.     增加一個字符 ( abed 變成 abedd)

          3.     刪除一個字符(如 jackbllog 變成 jackblog

          針對于 jackbllogjackblog 只需要刪除一個或增加一個 l 就可以把兩個字符串變為相同。把這種操作需要的次數定義為兩個字符串的距離 L, 則相似度定義為 1/(L+1) 即距離加一的倒數。那么jackbllogjackblog的相似度為 1/1+1=1/2=0.5 也就是所兩個字符串的相似度是 0.5,說明兩個字符串已經很接近啦。

          任意兩個字符串的距離都是有限的,都不會超過他們的長度之和,算法設計中我們并不在乎通過一系列的修改后,得到的兩個相同字符串是什么樣子。所以每次只需一步操作,并遞歸的進行下一計算。JAVA 的實現如下:

           1/**
           2 * 
           3 */

           4package org.blogjava.arithmetic;
           5
           6import java.util.HashMap;
           7import java.util.Map;
           8
           9/**
          10 * @author jack.wang
          11 * 
          12 */

          13public class StringDistance {
          14
          15    public static final Map<String, String> DISTANCE_CACHE = new HashMap<String, String>();
          16
          17    private static int caculateStringDistance(byte[] firstStr, int firstBegin,
          18            int firstEnd, byte[] secondStr, int secondBegin, int secondEnd) {
          19        String key = makeKey(firstStr, firstBegin, secondStr, secondBegin);
          20        if (DISTANCE_CACHE.get(key) != null{
          21            return Integer.parseInt(DISTANCE_CACHE.get(key));
          22        }
           else {
          23            if (firstBegin >= firstEnd) {
          24                if (secondBegin >= secondEnd) {
          25                    return 0;
          26                }
           else {
          27                    return secondEnd - secondBegin + 1;
          28                }

          29            }

          30            if (secondBegin >= secondEnd) {
          31                if (firstBegin >= firstEnd) {
          32                    return 0;
          33                }
           else {
          34                    return firstEnd - firstBegin + 1;
          35                }

          36            }

          37            if (firstStr[firstBegin] == secondStr[secondBegin]) {
          38                return caculateStringDistance(firstStr, firstBegin + 1,
          39                        firstEnd, secondStr, secondBegin + 1, secondEnd);
          40            }
           else {
          41                int oneValue = caculateStringDistance(firstStr, firstBegin + 1,
          42                        firstEnd, secondStr, secondBegin + 2, secondEnd);
          43                int twoValue = caculateStringDistance(firstStr, firstBegin + 2,
          44                        firstEnd, secondStr, secondBegin + 1, secondEnd);
          45                int threeValue = caculateStringDistance(firstStr,
          46                        firstBegin + 2, firstEnd, secondStr, secondBegin + 2,
          47                        secondEnd);
          48                DISTANCE_CACHE.put(key, String.valueOf(min(oneValue, twoValue,
          49                        threeValue) + 1));
          50                return min(oneValue, twoValue, threeValue) + 1;
          51            }

          52        }

          53    }

          54
          55    public static float similarity(String stringOne, String stringTwo) {
          56        return 1f / (caculateStringDistance(stringOne.getBytes(), 0, stringOne
          57                .getBytes().length - 1, stringTwo.getBytes(), 0, stringOne
          58                .getBytes().length - 1+ 1);
          59    }

          60
          61    private static int min(int oneValue, int twoValue, int threeValue) {
          62        return oneValue > twoValue ? twoValue
          63                : oneValue > threeValue ? threeValue : oneValue;
          64    }

          65
          66    private static String makeKey(byte[] firstStr, int firstBegin,
          67            byte[] secondStr, int secondBegin) {
          68        StringBuffer sb = new StringBuffer();
          69        return sb.append(firstStr).append(firstBegin).append(secondStr).append(
          70                secondBegin).toString();
          71    }

          72
          73    /**
          74     * @param args
          75     */

          76    public static void main(String[] args) {
          77        float i = StringDistance.similarity("jacklovvedyou""jacklodveyou");
          78        System.out.println(i);
          79    }

          80}

          81




          本博客為學習交流用,凡未注明引用的均為本人作品,轉載請注明出處,如有版權問題請及時通知。由于博客時間倉促,錯誤之處敬請諒解,有任何意見可給我留言,愿共同學習進步。
          posted on 2009-01-19 23:53 Jack.Wang 閱讀(11011) 評論(9)  編輯  收藏 所屬分類: 開發技術數學&算法

          Feedback

          # re: 計算字符串相似度的簡易算法 2009-01-20 09:37 Anonymous
          看看算法書再來吧  回復  更多評論
            

          # re: 計算字符串相似度的簡易算法[未登錄] 2009-01-20 10:44 IceRao
          使用向量吧。  回復  更多評論
            

          # re: 計算字符串相似度的簡易算法 2009-01-20 10:59 夜弓
          字符串不是字節流
          相似度是不好這樣簡單算的
          比如
          helloworld
          hollywood
          9個字母里面就有6個相同
          顯然不是那么簡單回事  回復  更多評論
            

          # re: 計算字符串相似度的簡易算法 2009-01-20 16:29 Anonymous
          計算編輯距離是個好想法,但還是有局限性的

          另外你的相似度計算公式從分布上并不很natural,比如兩個長度在30的單詞,如果編輯距離為1,他們的相似度會比兩個長度在5編輯距離為1的單詞要更加高一些(我覺得這樣的想法會更natural一點)。

          從編輯距離本身的定義角度,我覺得還是不適合作為字符串相似的量度的,但可以作為輔助手段來對可能的錯誤輸入產生提示。  回復  更多評論
            

          # re: 計算字符串相似度的簡易算法 2009-01-20 20:21 Jack.Wang
          這么多人回復?。?
          @Anonymous
          恩,說的很好,謝謝啦!之前沒看相關的算法書,只是有這個想法!順便寫了寫!應該有更好的量度來計算兩個字符串的相似度!等看看算法書或者有 blog 友貼貼!  回復  更多評論
            

          # re: 計算字符串相似度的簡易算法 2009-08-29 23:41 cricket
          遞歸算法的復雜度非常高,動態規劃算法能把復雜度降到O(M*N),改進后能到O(N+K^2),自動機和bit-parallelism算法甚至能到O(N)  回復  更多評論
            

          # re: 計算字符串相似度的簡易算法 2009-10-14 14:54 yeluolei
          有那么簡單么……  回復  更多評論
            

          # re: 計算字符串相似度的簡易算法 2009-12-17 14:02 黃凱
          是的,使用編輯距離(尤其是改良后的Levenshtein算法)其算法復雜度可以縮短至O(2k+1)。不過lz的思想和Levenshtein算法的初衷本質上是一致的,還是值得贊賞的,可惜人家比你早很多年提出來~  回復  更多評論
            

          # re: 計算字符串相似度的簡易算法 2010-03-25 09:18 szx
          老大,這是《編程之美》上的原題源代碼  回復  更多評論
            

          主站蜘蛛池模板: 仁化县| 南皮县| 哈巴河县| 湘阴县| 铅山县| 射阳县| 库尔勒市| 青海省| 宣化县| 民和| 开原市| 五峰| 托克逊县| 兴山县| 朝阳市| 屏山县| 临沭县| 称多县| 新龙县| 达拉特旗| 疏勒县| 盖州市| 蕉岭县| 清河县| 常熟市| 阳西县| 正宁县| 昌图县| 含山县| 河源市| 平利县| 东乡族自治县| 大渡口区| 永平县| 安宁市| 琼海市| 临澧县| 中阳县| 平陆县| 安平县| 汉阴县|