Skip to content

Commit

Permalink
feat: KMP 算法
Browse files Browse the repository at this point in the history
  • Loading branch information
originalix committed May 5, 2021
1 parent 830a0e2 commit 768c60c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 32 deletions.
16 changes: 8 additions & 8 deletions __test__/strings/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,12 @@ describe('字符串算法测试', () => {
})
})

// describe('KMP', () => {
// test('KMP 构造函数 lix', () => {
// const kmp = new KMP('ababac')
// expect(kmp).not.toBeNull()
// const index = kmp.search('aaaaabbbbbababacaaaaaaaaaaaaaaaaaa')
// expect(index).toBe(0)
// })
// })
describe('KMP', () => {
test('KMP 构造函数 lix', () => {
const kmp = new KMP('ababac')
expect(kmp).not.toBeNull()
const index = kmp.search('aaaaabbbbbababacaaaaaaaaaaaaaaaaaa')
expect(index).toBe(10)
})
})
})
47 changes: 23 additions & 24 deletions src/algs4/strings/kmp.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
const ACode = 97
const RADIX = 256

export default class KMP {
private pat: string
private dfa: number[][]

// 由模式字符串构造 DFA
constructor(pat: string) {
this.pat = pat
const M = pat.length
const R = 26
this.dfa = Array.from({ length: R }, () => [])
for (const sub of this.dfa) {
for (let i = 0; i < M; i++) {
sub[i] = null
}
this.dfa = new Array(RADIX)
const n = this.pat.length
for (let i = 0; i < RADIX; i++) {
this.dfa[i] = new Array(n).fill(0)
}
this.dfa[this.pat.charCodeAt(0) - ACode][0] = 1

for (let X = 0, j = 1; j < M; j++) {
for (let c = 0; c < R; c++) {
this.dfa[c][j] = this.dfa[c][X]
this.dfa[this.pat.charCodeAt(0)][0] = 1

// 计算 dfa[][curr]
for (let prev = 0, curr = 1; curr < n; curr++) {
for (let ch = 0; ch < RADIX; ch++) {
this.dfa[ch][curr] = this.dfa[ch][prev] // 复制匹配失败情况下的值
}
this.dfa[this.pat.charCodeAt(j) - ACode][j] = j + 1
X = this.dfa[this.pat.charCodeAt(j) - ACode][X]
this.dfa[this.pat.charCodeAt(curr)][curr] = curr + 1 // 设置匹配成功情况下的值
prev = this.dfa[this.pat.charCodeAt(curr)][prev] // 更新重启状态
}
}

search(txt: string): number {
// 在 txt 上模拟 DFA 的运行
search(txt: string) {
let i, j
const N = txt.length
const M = this.pat.length
for (i = 0, j = 0; i < N && j < M; i++) {
j = this.dfa[txt.charCodeAt(i) - ACode][j]
}
if (j === M) {
return i - M
} else {
return N
const m = this.pat.length
const n = txt.length
for (i = 0, j = 0; i < n && j < m; i++) {
j = this.dfa[txt.charCodeAt(i)][j]
}

// 找到匹配(到达模式字符串的结尾)则返回 i-m
return j === m ? i - m : -1
}
}

0 comments on commit 768c60c

Please sign in to comment.