从排序字符串数组中找到第一个前缀匹配的最有效算法?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从排序字符串数组中找到第一个前缀匹配的最有效算法?相关的知识,希望对你有一定的参考价值。
输入:
1)一个巨大的字符串SA排序数组;
2)前缀字符串P;
输出:
与输入前缀匹配的第一个字符串的索引(如果有)。如果没有这样的匹配,则输出将为-1。
例:
SA = {"ab", "abd", "abdf", "abz"}
P = "abd"
输出应为1(索引从0开始)。
做这种工作的算法最简单的方法是什么?
如果你只想这样做一次,使用binary search,如果另一方面你需要为许多不同的前缀做,但是在相同的字符串数组上,建立一个radix tree可能是一个好主意,在你每个构建树后抬头会很快。
它可以使用Suffix Tree在线性时间内完成。构建后缀树需要线性时间。
这只是一个修改过的二分搜索:
- 只检查每个元素中的字符数与搜索字符串中的字符数一样多;和
- 如果找到匹配项,请继续向后搜索(线性或通过进一步的二分搜索),直到找到不匹配的结果,然后返回最后一个匹配结果的索引。
FreeBSD内核使用Radix tree作为路由表,你应该检查一下。
我当前的解决方案是,而不是找到“前缀”,尝试找到“虚拟前缀”。
例如,前缀是“abd”,尝试查找虚拟前缀“abc(255)”。 (255)只表示最大字符数。找到“abc(255)”后。下一个单词应该是匹配“abd”的第一个单词(如果有的话)。
您是否能够预先计算所有可能的前缀?
如果是这样,您可以这样做,然后使用二进制搜索在预先计算的表中查找前缀。使用前缀将下标存储到所需的值。
我的解决方案:使用二分查找。
private static int search(String[] words, String searchPrefix) {
if (words == null || words.length == 0) {
return -1;
}
int low = 0;
int high = words.length - 1;
int searchPrefixLength = searchPrefix.length();
while (low <= high) {
int mid = low + (high - low) / 2;
String word = words[mid];
int compare = -1;
if (searchPrefixLength <= word.length()) {
compare = word.substring(0, searchPrefixLength).compareTo(searchPrefix);
}
if (compare == 0) {
return mid;
} else if (compare > 0) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
这是一个可能的解决方案(在Python中),它具有O(k.log(n))时间复杂度和O(1)额外空间复杂度(考虑n个字符串和k前缀长度)。
它执行二进制搜索的基本原理只考虑字符串的给定字符索引。如果存在,请继续下一个字符索引。如果在任何字符串中找不到任何前缀字符,则立即返回。
from typing import List
def first(items: List[str], prefix: str, i: int, c: str, left: int, right: int):
result = -1
while left <= right:
mid = left + ((right - left) // 2)
if ( i >= len(items[mid]) ):
left = mid + 1
elif (c < items[mid][i]):
right = mid - 1
elif (c > items[mid][i]):
left = mid + 1
else:
result = mid
right = mid - 1
return result
def last(items: List[str], prefix: str, i: int, c: str, left: int, right: int):
result = -1
while left <= right:
mid = left + ((right - left) // 2)
if ( i >= len(items[mid]) ):
left = mid + 1
elif (c < items[mid][i]):
right = mid - 1
elif (c > items[mid][i]):
left = mid + 1
else:
result = mid
left = mid + 1
return result
def is_prefix(items: List[str], prefix: str):
left = 0
right = len(items) - 1
for i in range(len(prefix)):
c = prefix[i]
left = first(items, prefix, i, c, left, right)
right = last(items, prefix, i, c, left, right)
if (left == -1 or right == -1):
return False
return True
# Test cases
a = ['ab', 'abjsiohjd', 'abikshdiu', 'ashdi','abcde Aasioudhf', 'abcdefgOAJ', 'aa', 'aaap', 'aas', 'asd', 'bbbbb', 'bsadiojh', 'iod', '0asdn', 'asdjd', 'bqw', 'ba']
a.sort()
print(a)
print(is_prefix(a, 'abcdf'))
print(is_prefix(a, 'abcde'))
print(is_prefix(a, 'abcdef'))
print(is_prefix(a, 'abcdefg'))
print(is_prefix(a, 'abcdefgh'))
print(is_prefix(a, 'abcde Aa'))
print(is_prefix(a, 'iod'))
print(is_prefix(a, 'ZZZZZZiod'))
这个要点可以在https://gist.github.com/lopespm/9790d60492aff25ea0960fe9ed389c0f找到
以上是关于从排序字符串数组中找到第一个前缀匹配的最有效算法?的主要内容,如果未能解决你的问题,请参考以下文章