對數據進行模糊匹配搜索(動態規劃、最長公共子串、最長公共子序列)

在搜索時常常在輸入一半或者輸入錯誤時,搜索引擎就給出智能提示。

搜索框

已知的搜索推薦主要包括以下幾個方面:

  • 包含:“清華” 和 “清華大學”
  • 相似:“聊天軟件” 和 “通訊軟件”
  • 相關:“明星” 和 “劉亦菲”
  • 糾錯:“好奇害死毛” 和 “好奇害死貓”

其中包含模糊匹配可以使用動態規劃算法解決,其他幾個則要大量數據進行機器學習纔行。

倘若要在一堆數據中對一個關鍵詞進行匹配搜索,傳統做法是把數據拆分開,然後遍歷他們,看看是否包含這個關鍵詞,對於 “fin” 和 “finish” 這樣存在包含關係的單詞來說是沒問題的,但是對於 “fish” 和 “finish” 這樣並不存在包含關係的單詞就失效了,這時候期望計算出兩個單詞的相似性,比如 “fish” 和 “finish” 都包含 “ish”,“ish” 的長度是 3,我們可以理解相似性爲 3。目前主流做法是通過最長公共子串來尋找兩個或多個已知字符串最長的子串。

注:深拷貝使用了依賴庫,需先安裝 npm install mazey --save

最長公共子串示例:

import { deepCopy } from 'mazey';

/**
 * @method calLongestCommonSubstring
 * @description 計算兩個字符串的最長公共子串
 * @param {String} aStr 字符串
 * @param {String} bStr 字符串
 * @return {Number} 長度
 */
function calLongestCommonSubstring (aStr, bStr) {
    const aLen = aStr.length;
    const bLen = bStr.length;
    // 創建二維數組並且深拷貝
    const arr = deepCopy(new Array(aLen).fill(new Array(bLen).fill(0)));
    for (let i = 0; i < aLen; ++i) {
        for (let j = 0; j < bLen; ++j) {
            if (aStr[i] === bStr[j]) {
                let baseNum = 0;
                if (i > 0 && j > 0) {
                    baseNum = arr[i-1][j-1];
                }
                arr[i][j] = baseNum + 1;
            }
        }
    }
    // 二維數組轉一維數組
    const arr1 = Array.prototype.concat.apply([], arr);
    // 獲取最長公共子串
    const maxLong = Math.max(...arr1);
    return maxLong;
}

calLongestCommonSubstring('fish', 'finish'); // 3

“fish” 和 “finish” 除了 “ish” 之外還共同包含 “f”,所以 “ish” + “f” 更好的表達其相似性(3 + 1 = 4),於是使用最長公共子序列對最長公共子串進行升級來查找所有序列中最長子序列,版本管理中使用的 git diff 就是建立在最長公共子序列的基礎上。

最長公共子序列示例:

import { deepCopy } from 'mazey';

/**
 * @method calLongestCommonSubsequence
 * @description 計算兩個字符串的最長公共子序列
 * @param {String} aStr 字符串
 * @param {String} bStr 字符串
 * @return {Number} 長度
 */
function calLongestCommonSubsequence (aStr, bStr) {
  const aLen = aStr.length;
  const bLen = bStr.length;
  const arr = deepCopy(new Array(aLen).fill(new Array(bLen).fill(0)));
  for (let i = 0; i < aLen; ++i) {
    for (let j = 0; j < bLen; ++j) {
      if (aStr[i] === bStr[j]) {
        let baseNum = 0;
        if (i > 0 && j > 0) {
          baseNum = arr[i - 1][j - 1];
        }
        arr[i][j] = baseNum + 1;
      } else {
        let [leftValue, topValue] = [0, 0];
        if (j > 0) {
          leftValue = arr[i][j - 1];
        }
        if (i > 0) {
          topValue = arr[i - 1][j];
        }
        arr[i][j] = Math.max(leftValue, topValue);
      }
    }
  }
  // 二維數組轉一維數組
  const arr1 = Array.prototype.concat.apply([], arr);
  // 獲取最長公共子串
  const maxLong = Math.max(...arr1);
  return maxLong;
}

calLongestCommonSubsequence('fish', 'finish'); // 4

參考

  1. 1143. 最長公共子序列 - 力扣(LeetCode)
  2. 搜索引擎如何做到模糊匹配?

版權聲明

本博客所有的原創文章,作者皆保留版權。轉載必須包含本聲明,保持本文完整,並以超鏈接形式註明作者後除和本文原始地址:https://blog.mazey.net/1595.html

(完)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章