Самый эффективный алгоритм для поиска первого префикса-сопоставления из отсортированного массива строк?

Входные данные:

1) огромный отсортированный массив строк SA;

2) префиксная строка P;

Выход:

Индекс первой строки, соответствующей входному префиксу, если таковой имеется. Если такого совпадения нет, вывод будет -1.

Пример:

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

Выход должен быть 1 (индекс начинается с 0).

Какой самый алгоритм способ сделать такую работу?

Ответы

Ответ 1

Если вы хотите сделать это один раз, используйте двоичный поиск, если, с другой стороны, вам нужно сделать это для множества разных префиксов, но в том же массиве строк, создание дерева оснований может быть хорошей идеей, после того, как вы построили дерево, каждый поиск будет очень быстрым.

Ответ 2

Это можно сделать в линейном режиме, используя Дерево суффикса. Построение дерева суффиксов занимает линейное время.

Ответ 3

Это просто измененный поиск пополам:

  • Проверять только количество символов в каждом элементе, как в строке поиска; и
  • Если вы найдете совпадение, продолжайте поиск в обратном направлении (либо линейно, либо путем дальнейшего поиска по бисекции), пока не найдете результат несоответствия, а затем верните индекс последнего результата сопоставления.

Ответ 4

Ядро FreeBSD использует дерево Radix для своей таблицы маршрутизации, вы должны проверить это.

Ответ 5

Мое текущее решение в том, что вместо того, чтобы найти "префикс", попробуйте найти "виртуальный префикс".

Например, префикс "abd", попробуйте найти виртуальный префикс "abc (255)". (255) просто представляет собой номер max char. После нахождения "abc (255)". Следующее слово должно быть первым словом, соответствующим "abd", если оно есть.

Ответ 6

Вы можете предварительно вычислить все возможные префиксы?

Если это так, вы можете это сделать, а затем используйте двоичный поиск, чтобы найти префикс в таблице с предварительно рассчитанными значениями. Сохраните индекс до нужного значения с помощью префикса.

Ответ 7

Мое решение: использовал бинарный поиск.

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

Ответ 8

Вот возможное решение (в 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.