从排序字符串数组中找到第一个前缀匹配的最有效算法?

问题描述 投票:14回答:8

输入:

1)一个巨大的字符串SA排序数组;

2)前缀字符串P;

输出:

与输入前缀匹配的第一个字符串的索引(如果有)。如果没有这样的匹配,则输出将为-1。

例:

SA = {"ab", "abd", "abdf", "abz"}
P = "abd"

输出应为1(索引从0开始)。

做这种工作的算法最简单的方法是什么?

arrays string algorithm sorting search
8个回答
19
投票

如果你只想这样做一次,使用binary search,如果另一方面你需要为许多不同的前缀做,但是在相同的字符串数组上,建立一个radix tree可能是一个好主意,在你每个构建树后抬头会很快。


3
投票

它可以使用Suffix Tree在线性时间内完成。构建后缀树需要线性时间。


2
投票

这只是一个修改过的二分搜索:

  • 只检查每个元素中的字符数与搜索字符串中的字符数一样多;和
  • 如果找到匹配项,请继续向后搜索(线性或通过进一步的二分搜索),直到找到不匹配的结果,然后返回最后一个匹配结果的索引。

0
投票

FreeBSD内核使用Radix tree作为路由表,你应该检查一下。


0
投票

我当前的解决方案是,而不是找到“前缀”,尝试找到“虚拟前缀”。

例如,前缀是“abd”,尝试查找虚拟前缀“abc(255)”。 (255)只表示最大字符数。找到“abc(255)”后。下一个单词应该是匹配“abd”的第一个单词(如果有的话)。


0
投票

您是否能够预先计算所有可能的前缀?

如果是这样,您可以这样做,然后使用二进制搜索在预先计算的表中查找前缀。使用前缀将下标存储到所需的值。


0
投票

我的解决方案:使用二分查找。

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;
    }

0
投票

这是一个可能的解决方案(在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找到

© www.soinside.com 2019 - 2024. All rights reserved.