웹 프론트엔드 JS 튜토리얼 JavaScript의 데이터 구조 및 알고리즘(5): 클래식 KMP 알고리즘_javascript 기술

JavaScript의 데이터 구조 및 알고리즘(5): 클래식 KMP 알고리즘_javascript 기술

May 16, 2016 pm 03:54 PM
javascript kmp 데이터 구조 연산 권위 있는

KMP 알고리즘과 BM 알고리즘

KMP는 접두사 일치와 BM 접미사 일치에 대한 고전적인 알고리즘으로 접두사 일치와 접미사 일치의 차이는 비교 순서에만 있음을 알 수 있습니다

접두사 일치 의미: 패턴 문자열과 상위 문자열의 비교는 왼쪽에서 오른쪽으로 이루어지며, 패턴 문자열의 이동도 왼쪽에서 오른쪽으로 이루어집니다

접미사 일치를 의미합니다. 패턴 문자열과 상위 문자열의 비교는 오른쪽에서 왼쪽으로 이루어지며, 패턴 문자열의 이동은 왼쪽에서 오른쪽으로 이루어집니다.

이전 장을 통해 BF 알고리즘도 접두사 알고리즘임이 분명하지만 일대일 매칭의 효율성은 매우 오만합니다. 당연히 O(는 언급할 필요가 없습니다. mn). 온라인에서 짜증나는 KMP는 기본적으로 높은 수준의 경로를 취하고 있으며 가장 현실적인 방법으로 설명하려고 노력했습니다. >

KMP

KMP도 접두사 알고리즘의 최적화된 버전입니다. KMP라고 불리는 이유는 Knuth, Morris, Pratt 세 이름의 약어입니다. BF와 비교할 때 KMP 알고리즘의 최적화 포인트는 "the"입니다. 각 후진 이동 거리" 각 패턴 문자열의 이동 거리를 동적으로 조정합니다. BF는 매번 1입니다.

꼭 KMP일 필요는 없습니다

그림과 같이 BF와 KMP 사전 알고리즘의 차이점을 비교합니다

사진을 비교해 보니 다음과 같습니다.

텍스트 문자열 T에서 패턴 문자열 P를 검색합니다. 여섯 번째 문자 c와 자연스럽게 일치하면 두 번째 수준이 일치하지 않음을 발견합니다. 그러면 BF 방법은 전체 패턴 문자열 P를 한 자리 이동하는 것입니다. 그리고 KMP는 두 곳씩 옮기는 것입니다.

우리는 BF의 매칭 방식을 알고 있는데 왜 KMP는 한 자리, 세 자리, 네 자리가 아닌 두 자리를 이동하는 걸까요?

이전 그림을 설명하자면, 패턴 문자열 P는 ababa와 일치하면 정확하고, c와 일치하면 틀리게 됩니다. 그러면 KMP 알고리즘의 아이디어는 다음과 같습니다. 우리는 이 정보를 사용하여 "검색 위치"를 비교된 위치로 다시 이동하는 것이 아니라 계속해서 뒤로 이동하므로 효율성이 향상됩니다.

그럼 질문은 이동해야 할 직위가 몇 개인지 어떻게 알 수 있느냐는 것입니다.

이 오프셋 알고리즘 KMP의 작성자는 이를 요약했습니다.


코드 복사 코드는 다음과 같습니다.

자리 이동 = 일치하는 문자 수 - 해당 부분 일치 값
오프셋 알고리즘은 텍스트 문자열이 아닌 하위 문자열에만 관련되므로 여기서는 특별한 주의가 필요합니다
그렇다면 하위 문자열에서 일치하는 문자 수와 해당 부분 일치 값을 어떻게 이해할 수 있을까요?

일치하는 문자:

코드 복사 코드는 다음과 같습니다.
T : 아바바바바밥
p :아바백

p의 빨간색 표시는 일치하는 문자이므로 이해하기 쉽습니다

부분 일치 값:

이것이 핵심 알고리즘인데, 이해하기도 어렵습니다

만약:


코드 복사 코드는 다음과 같습니다.
T:aaronaabbcc
P:아로나크


이 텍스트를 관찰하면 c를 일치시킬 때 오류가 발생하면 이전 구조를 기반으로 다음 이동이 어디에 있을까요?
코드 복사 코드는 다음과 같습니다.
aaronaabbcc
아로나악

즉, 패턴 텍스트 내에서 특정 문자 단락의 시작과 끝이 동일하면 자연 필터링 중에 해당 단락을 건너뛸 수 있습니다.

이 규칙을 알면 주어진 부분 일치 테이블 알고리즘은 다음과 같습니다.

먼저 "접두사"와 "접미사"라는 두 가지 개념을 이해해야 합니다. "접두사"는 마지막 문자를 제외한 문자열의 모든 머리 조합을 나타내고 "접미사"는 첫 번째 문자를 제외한 문자열의 모든 꼬리 조합을 나타냅니다.

"부분 일치 값"은 "접두사"와 "접미사" 사이의 가장 긴 공통 요소의 길이입니다."

BF전이라면 아로나크의 디비전을 살펴보겠습니다

BF의 변위: a,aa,aar,aaro,aaron,aarona,aaronaa,aaronaac

그렇다면 KMP의 부서는 어떨까요? 여기서 접두사와 접미사를 소개해야 합니다

먼저 KMP 부분 매칭 테이블의 결과를 살펴보겠습니다.

코드 복사 코드는 다음과 같습니다.

a r o n a a c
[0, 1, 0, 0, 0, 1, 2, 0]

확실히 헷갈리는데 걱정하지 마세요, 접두사, 접미사로 풀어보겠습니다

코드 복사 코드는 다음과 같습니다.

일치 문자열: "Aaron"
접두사: A, Aa, Aar, Aaro
접미사: aron,ron,on,n

이동 위치 : 실제로 일치하는 각 문자의 접두사와 접미사를 비교하여 동일한지 확인한 다음 전체 길이를 계산하는 것입니다

부분 매칭 테이블 분해

KMP의 일치 테이블 알고리즘, 여기서 p는 접두사, n은 접미사, r은 결과를 나타냅니다.

코드 복사 코드는 다음과 같습니다.

a,        p=>0, n=>0 r = 0

aa,      p=>[a], n=>[a], r = a.length =>

aar, p=>[a,aa], n=>[r,ar] ,r = 0

aaro, p=>[a,aa,aar], n=>[o,ra,aro] ,r = 0

아론 p=>[a,aa,aar,aaro], n=>[n,on,ron,aron] ,r = 0

aarona, p=>[a,aa,aar,aaro,aaron], n=>[a,na,ona,rona,arona] ,r = a.length = 1

aaronaa, p=>[a,aa,aar,aaro,aaron,aarona], n=>[a,aa,naa,onaa,ronaa,aronaa] , r = Math.max(a.length ,aa.길이) = 2

aaronaac p=>[a,aa,aar,aaro,aaron,aarona], n=>[c,ac,aac,naac,onaac,ronaac] r = 0


BF 알고리즘과 유사하게 먼저 일치 가능한 각 첨자의 위치를 ​​분해하고 캐시합니다. 일치 시 이 "부분 일치 테이블"을 사용하여 이동해야 하는 자릿수를 찾습니다.

그래서 aaronaac의 매칭 테이블의 최종 결과는 0,1,0,0,0,1,2,0입니다.

JS 버전의 KMP는 아래와 같이 구현되며, 2가지 유형이 있습니다

KMP 구현(1): KMP 캐싱 매칭 테이블

KMP 구현(2): 다음 KMP를 동적으로 계산


KMP 구현(1)

매칭 테이블

KMP 알고리즘에서 가장 중요한 것은 매칭 테이블입니다. 매칭 테이블이 필요하지 않다면 BF를 추가하는 것이 KMP입니다.

매칭 테이블이 다음 변위 카운트를 결정합니다

위 매칭 테이블의 규칙을 기반으로 kmpGetStrPartMatchValue 메소드를 설계합니다


function kmpGetStrPartMatchValue(str) {
   var prefix = [];
   var suffix = [];
   var partMatch = [];
   for (var i = 0, j = str.length; i < j; i++) {
    var newStr = str.substring(0, i + 1);
    if (newStr.length == 1) {
     partMatch[i] = 0;
    } else {
     for (var k = 0; k < i; k++) {
      //前缀
      prefix[k] = newStr.slice(0, k + 1);
      //后缀
      suffix[k] = newStr.slice(-k - 1);
      //如果相等就计算大小,并放入结果集中
      if (prefix[k] == suffix[k]) {
       partMatch[i] = prefix[k].length;
      }
     }
     if (!partMatch[i]) {
      partMatch[i] = 0;
     }
    }
   }
   return partMatch;
  }
로그인 후 복사

완전히 KMP의 일치 테이블 알고리즘 구현에 따라 a->aa->aar->aaro->aaron->aarona->는 str.substring(0, i 1) aaronaa-aaronaac

그런 다음 각 분해에서 접두사와 접미사를 통해 공통 요소의 길이를 계산합니다

백오프 알고리즘

KMP도 BF를 완전히 전송할 수 있습니다. 유일한 수정 사항은 KMP가 역추적할 때 BF가 직접 1을 추가한다는 것입니다.


//子循环
for (var j = 0; j < searchLength; j++) {
  //如果与主串匹配
  if (searchStr.charAt(j) == sourceStr.charAt(i)) {
    //如果是匹配完成
    if (j == searchLength - 1) {
     result = i - j;
     break;
    } else {
     //如果匹配到了,就继续循环,i++是用来增加主串的下标位
     i++;
    }
  } else {
   //在子串的匹配中i是被叠加了
   if (j > 1 && part[j - 1] > 0) {
    i += (i - j - part[j - 1]);
   } else {
    //移动一位
    i = (i - j)
   }
   break;
  }
}
로그인 후 복사
빨간색 표시가 KMP의 핵심 포인트입니다. next 값 = 일치하는 문자 수 - 해당 부분 일치 값

KMP 알고리즘 완성

<!doctype html><div id="test2"><div><script type="text/javascript">
 

  function kmpGetStrPartMatchValue(str) {
   var prefix = [];
   var suffix = [];
   var partMatch = [];
   for (var i = 0, j = str.length; i < j; i++) {
    var newStr = str.substring(0, i + 1);
    if (newStr.length == 1) {
     partMatch[i] = 0;
    } else {
     for (var k = 0; k < i; k++) {
      //取前缀
      prefix[k] = newStr.slice(0, k + 1);
      suffix[k] = newStr.slice(-k - 1);
      if (prefix[k] == suffix[k]) {
       partMatch[i] = prefix[k].length;
      }
     }
     if (!partMatch[i]) {
      partMatch[i] = 0;
     }
    }
   }
   return partMatch;
  }



function KMP(sourceStr, searchStr) {
  //生成匹配表
  var part     = kmpGetStrPartMatchValue(searchStr);
  var sourceLength = sourceStr.length;
  var searchLength = searchStr.length;
  var result;
  var i = 0;
  var j = 0;

  for (; i < sourceStr.length; i++) { //最外层循环,主串

    //子循环
    for (var j = 0; j < searchLength; j++) {
      //如果与主串匹配
      if (searchStr.charAt(j) == sourceStr.charAt(i)) {
        //如果是匹配完成
        if (j == searchLength - 1) {
         result = i - j;
         break;
        } else {
         //如果匹配到了,就继续循环,i++是用来增加主串的下标位
         i++;
        }
      } else {
       //在子串的匹配中i是被叠加了
       if (j > 1 && part[j - 1] > 0) {
        i += (i - j - part[j - 1]);
       } else {
        //移动一位
        i = (i - j)
       }
       break;
      }
    }

    if (result || result == 0) {
     break;
    }
  }


  if (result || result == 0) {
   return result
  } else {
   return -1;
  }
}

 var s = "BBC ABCDAB ABCDABCDABDE";
 var t = "ABCDABD";


 show('indexOf',function() {
  return s.indexOf(t)
 })

 show('KMP',function() {
  return KMP(s,t)
 })

 function show(bf_name,fn) {
  var myDate = +new Date()
  var r = fn();
  var div = document.createElement('div')
  div.innerHTML = bf_name +'算法,搜索位置:' + r + ",耗时" + (+new Date() - myDate) + "ms";
   document.getElementById("test2").appendChild(div);
 }


</script></div></div>

로그인 후 복사

KMP(二)

第一种kmp的算法很明显,是通过缓存查找匹配表也就是常见的空间换时间了。那么另一种就是时时查找的算法,通过传递一个具体的完成字符串,算出这个匹配值出来,原理都一样

生成缓存表的时候是整体全部算出来的,我们现在等于只要挑其中的一条就可以了,那么只要算法定位到当然的匹配即可

next算法

function next(str) {
  var prefix = [];
  var suffix = [];
  var partMatch;
  var i = str.length
  var newStr = str.substring(0, i + 1);
  for (var k = 0; k < i; k++) {
   //取前缀
   prefix[k] = newStr.slice(0, k + 1);
   suffix[k] = newStr.slice(-k - 1);
   if (prefix[k] == suffix[k]) {
    partMatch = prefix[k].length;
   }
  }
  if (!partMatch) {
   partMatch = 0;
  }
  return partMatch;
}
로그인 후 복사

其实跟匹配表是一样的,去掉了循环直接定位到当前已成功匹配的串了

完整的KMP.next算法

<!doctype html><div id="testnext"><div><script type="text/javascript">
 
  function next(str) {
    var prefix = [];
    var suffix = [];
    var partMatch;
    var i = str.length
    var newStr = str.substring(0, i + 1);
    for (var k = 0; k < i; k++) {
     //取前缀
     prefix[k] = newStr.slice(0, k + 1);
     suffix[k] = newStr.slice(-k - 1);
     if (prefix[k] == suffix[k]) {
      partMatch = prefix[k].length;
     }
    }
    if (!partMatch) {
     partMatch = 0;
    }
    return partMatch;
  }

  function KMP(sourceStr, searchStr) {
    var sourceLength = sourceStr.length;
    var searchLength = searchStr.length;
    var result;
    var i = 0;
    var j = 0;

    for (; i < sourceStr.length; i++) { //最外层循环,主串

      //子循环
      for (var j = 0; j < searchLength; j++) {
        //如果与主串匹配
        if (searchStr.charAt(j) == sourceStr.charAt(i)) {
          //如果是匹配完成
          if (j == searchLength - 1) {
           result = i - j;
           break;
          } else {
           //如果匹配到了,就继续循环,i++是用来增加主串的下标位
           i++;
          }
        } else {
         if (j > 1) {
          i += i - next(searchStr.slice(0,j));
         } else {
          //移动一位
          i = (i - j)
         }
         break;
        }
      }

      if (result || result == 0) {
       break;
      }
    }


    if (result || result == 0) {
     return result
    } else {
     return -1;
    }
  }

 var s = "BBC ABCDAB ABCDABCDABDE";
 var t = "ABCDAB";


  show('indexOf',function() {
   return s.indexOf(t)
  })

  show('KMP.next',function() {
   return KMP(s,t)
  })

  function show(bf_name,fn) {
   var myDate = +new Date()
   var r = fn();
   var div = document.createElement('div')
   div.innerHTML = bf_name +'算法,搜索位置:' + r + ",耗时" + (+new Date() - myDate) + "ms";
    document.getElementById("testnext").appendChild(div);
  }

</script></div></div>

로그인 후 복사

git代码下载: https://github.com/JsAaron/data_structure

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

C++에서 기계 학습 알고리즘 구현: 일반적인 과제 및 솔루션 C++에서 기계 학습 알고리즘 구현: 일반적인 과제 및 솔루션 Jun 03, 2024 pm 01:25 PM

C++의 기계 학습 알고리즘이 직면하는 일반적인 과제에는 메모리 관리, 멀티스레딩, 성능 최적화 및 유지 관리 가능성이 포함됩니다. 솔루션에는 스마트 포인터, 최신 스레딩 라이브러리, SIMD 지침 및 타사 라이브러리 사용은 물론 코딩 스타일 지침 준수 및 자동화 도구 사용이 포함됩니다. 실제 사례에서는 Eigen 라이브러리를 사용하여 선형 회귀 알고리즘을 구현하고 메모리를 효과적으로 관리하며 고성능 행렬 연산을 사용하는 방법을 보여줍니다.

C++sort 함수의 기본 원리와 알고리즘 선택을 살펴보세요. C++sort 함수의 기본 원리와 알고리즘 선택을 살펴보세요. Apr 02, 2024 pm 05:36 PM

C++정렬 함수의 맨 아래 계층은 병합 정렬을 사용하고 복잡도는 O(nlogn)이며 빠른 정렬, 힙 정렬 및 안정 정렬을 포함한 다양한 정렬 알고리즘 선택을 제공합니다.

Java 함수 비교를 사용하여 복잡한 데이터 구조 비교 Java 함수 비교를 사용하여 복잡한 데이터 구조 비교 Apr 19, 2024 pm 10:24 PM

Java에서 복잡한 데이터 구조를 사용할 때 Comparator는 유연한 비교 메커니즘을 제공하는 데 사용됩니다. 구체적인 단계에는 비교기 클래스 정의, 비교 논리를 정의하기 위한 비교 메서드 재작성 등이 포함됩니다. 비교기 인스턴스를 만듭니다. Collections.sort 메서드를 사용하여 컬렉션 및 비교기 인스턴스를 전달합니다.

탐지 알고리즘 개선: 고해상도 광학 원격탐사 이미지에서 표적 탐지용 탐지 알고리즘 개선: 고해상도 광학 원격탐사 이미지에서 표적 탐지용 Jun 06, 2024 pm 12:33 PM

01 전망 요약 현재로서는 탐지 효율성과 탐지 결과 간의 적절한 균형을 이루기가 어렵습니다. 우리는 광학 원격 탐사 이미지에서 표적 감지 네트워크의 효과를 향상시키기 위해 다층 특징 피라미드, 다중 감지 헤드 전략 및 하이브리드 주의 모듈을 사용하여 고해상도 광학 원격 감지 이미지에서 표적 감지를 위한 향상된 YOLOv5 알고리즘을 개발했습니다. SIMD 데이터 세트에 따르면 새로운 알고리즘의 mAP는 YOLOv5보다 2.2%, YOLOX보다 8.48% 우수하여 탐지 결과와 속도 간의 균형이 더 잘 이루어졌습니다. 02 배경 및 동기 원격탐사 기술의 급속한 발전으로 항공기, 자동차, 건물 등 지구 표면의 많은 물체를 묘사하기 위해 고해상도 광학 원격탐사 영상이 활용되고 있다. 원격탐사 이미지 해석에서 물체 감지

Java 데이터 구조 및 알고리즘: 심층 설명 Java 데이터 구조 및 알고리즘: 심층 설명 May 08, 2024 pm 10:12 PM

데이터 구조와 알고리즘은 Java 개발의 기초입니다. 이 기사에서는 Java의 주요 데이터 구조(예: 배열, 연결 목록, 트리 등)와 알고리즘(예: 정렬, 검색, 그래프 알고리즘 등)을 자세히 살펴봅니다. 이러한 구조는 배열을 사용하여 점수를 저장하고, 연결된 목록을 사용하여 쇼핑 목록을 관리하고, 스택을 사용하여 재귀를 구현하고, 대기열을 사용하여 스레드를 동기화하고, 트리 및 해시 테이블을 사용하여 빠른 검색 및 인증을 저장하는 등 실제 사례를 통해 설명됩니다. 이러한 개념을 이해하면 효율적이고 유지 관리가 가능한 Java 코드를 작성할 수 있습니다.

58 초상화 플랫폼 구축에 알고리즘 적용 58 초상화 플랫폼 구축에 알고리즘 적용 May 09, 2024 am 09:01 AM

1. 58초상화 플랫폼 구축 배경 먼저, 58초상화 플랫폼 구축 배경에 대해 말씀드리겠습니다. 1. 기존 프로파일링 플랫폼의 전통적인 사고로는 더 이상 충분하지 않습니다. 사용자 프로파일링 플랫폼을 구축하려면 여러 비즈니스 라인의 데이터를 통합하여 정확한 사용자 초상화를 구축하는 데이터 웨어하우스 모델링 기능이 필요합니다. 그리고 알고리즘 측면의 기능을 제공해야 하며, 마지막으로 사용자 프로필 데이터를 효율적으로 저장, 쿼리 및 공유하고 프로필 서비스를 제공할 수 있는 데이터 플랫폼 기능도 있어야 합니다. 자체 구축한 비즈니스 프로파일링 플랫폼과 중간 사무실 프로파일링 플랫폼의 주요 차이점은 자체 구축한 프로파일링 플랫폼이 단일 비즈니스 라인에 서비스를 제공하고 필요에 따라 사용자 정의할 수 있다는 것입니다. 모델링하고 보다 일반적인 기능을 제공합니다. 2.58 Zhongtai 초상화 구성 배경의 사용자 초상화

PHP 데이터 구조: AVL 트리의 균형, 효율적이고 질서 있는 데이터 구조 유지 PHP 데이터 구조: AVL 트리의 균형, 효율적이고 질서 있는 데이터 구조 유지 Jun 03, 2024 am 09:58 AM

AVL 트리는 빠르고 효율적인 데이터 작업을 보장하는 균형 잡힌 이진 검색 트리입니다. 균형을 이루기 위해 좌회전 및 우회전 작업을 수행하고 균형을 위반하는 하위 트리를 조정합니다. AVL 트리는 높이 균형을 활용하여 노드 수에 비해 트리 높이가 항상 작게 되도록 함으로써 로그 시간 복잡도(O(logn)) 검색 작업을 달성하고 대규모 데이터 세트에서도 데이터 구조의 효율성을 유지합니다.

글로벌 그래프 강화 기반 뉴스 추천 알고리즘 글로벌 그래프 강화 기반 뉴스 추천 알고리즘 Apr 08, 2024 pm 09:16 PM

작성자 | 검토자: Wang Hao | Chonglou News 앱은 사람들이 일상 생활에서 정보 소스를 얻는 중요한 방법입니다. 2010년경 해외의 인기 뉴스 앱에는 Zite, Flipboard 등이 있었고, 국내 인기 뉴스 앱은 4대 포털이 주를 이루었습니다. 터우탸오(Toutiao)로 대표되는 신시대 뉴스 추천 상품의 인기로 뉴스 앱은 새로운 시대에 접어들었습니다. 기술 기업의 경우 어느 기업이든 정교한 뉴스 추천 알고리즘 기술을 숙지하면 기본적으로 기술 수준에서 주도권과 발언권을 갖게 됩니다. 오늘은 RecSys2023 최우수 장편 논문 후보 추천 논문인 GoingBeyondLocal:GlobalGraph-EnhancedP를 살펴보겠습니다.

See all articles