Сравнить два списка в Python с o (n) сложностью

#python #list

#python #Список

Вопрос:

У меня есть два списка, и я хочу найти ключевые слова из инструкций, и если в инструкции есть это конкретное ключевое слово, то я должен вернуть это ключевое слово. Я делаю это в o(n^2) . Могу ли я сделать это в o(n) или в каком-либо другом, меньшей сложности?

 keywords = ['name', 'class', 'school', 'address']

statements = ['name is hello', 'name is not hello', 'school is hello', 'address is hello']

for key in keywords :
    for statement in statements :
            string = statement
            if string.find(key) != -1:
            print(key)
  

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

Комментарии:

1. Почему существует return ?

2. Это просто псевдокод, вы можете рассмотреть инструкцию print там. Пожалуйста, предложите некоторую логику.

3. Вы сравниваете их по порядку, т.Е. ключевые слова [0] против операторов [0], ключевые слова [1] против операторов [1] и т.д.?

4. Нет, все инструкции нужно сравнивать со всеми ключевыми словами.

Ответ №1:

Сделайте свой список ключевых слов набором. Таким образом, если вы хотите проверить, является ли слово ключевым словом, это поиск O (1). (Если вас волнует сложность пространства, тогда используйте вместо этого исходное дерево)

 words = {'name', 'class', ...}
  

Затем выполните итерацию по каждому слову в ваших утверждениях следующим образом:

 for statement in statements:
    for word in statement.split():
        if word in words:
            print(word)
  

O(n * m) , где m — длина самой длинной строки. Я не уверен, насколько это эффективно str.split() или как именно это работает, но вы могли бы уменьшить сложность с пробелами здесь, находя каждое слово вручную, просматривая statement и проверяя наличие пробелов, вместо создания списка в памяти.

Комментарии:

1. Но здесь также есть два цикла for , не означает ли это, что это даст сложность o (n ^ 2)?

2. @user Два цикла for не обязательно означают O (n ^ 2). В этом случае n длина каждого цикла for неодинакова. n — длина внешнего цикла for (количество элементов в statements , а m — (максимальная) длина внутреннего цикла for (количество слов в statement )

3. я пробовал это в своем коде, но все равно сложность почти равна o (n ^ 2). Однако спасибо за вашу помощь.

Ответ №2:

Если все, что вы хотите, это найти, существует ли какой-либо ключ в keywords в каких str.join -либо операторах, попробуйте сначала использовать:

 joined_statements = ' '.join(statements)
for key in keywords:
    if key in joined_statements:
        print(key)
  

Вывод:

 name
school
address
  

Комментарии:

1. Этот код даст обобщенный ответ. Он не скажет, в каком операторе было это ключевое слово. Мне это тоже было нужно.

2. in будет O (n). Смотрите здесь -> wiki. python.org/moin/TimeComplexity (x в s)

Ответ №3:

вместо того, чтобы делать

если string.find(ключ) != -1:

вы можете просто сделать

если ключ в строке:

Но в любом случае отступ неверен, и этот возврат в любом случае не должен работать.

вместо этого вы могли бы сделать что-то вроде этого:

 keywords = ['name', 'class', 'school', 'address']
checkedkeywords = []

statements = ['name is hello', 'name is not hello', 'school is hello', 'address is hello']

for key in keywords :
    for statement in statements :
            string = statement
            if key in string:
              checkedkeywords.append(key)

print(checkedkeywords)  

Надеюсь, это поможет и удачи!

Комментарии:

1. Тем не менее, это в o (n ^ 2) сложности.

Ответ №4:

Итак, вам нужно использовать подход ОБРАТНОГО ИНДЕКСИРОВАНИЯ для решения этой проблемы.

Создайте пустой словарь, lookup_dict={}

Теперь выполните цикл по каждому слову в каждом операторе и сохраните STATEMENTS_INDEX, соответствующий этому слову, как описано ниже.

statements = ['name is hello', 'name is not hello', 'school is hello', 'address is hello']

 lookup_dict= {
          'name': [0,1], # Denoting 'name' keyword comes in index 0 and 1
          'is': [0,1,2,3],
          'hello':[0,1,2,3],
          'not':[1],
          'address':[3]
 }
  

Теперь, как только вы создадите свои индексы, что обычно является одноразовой операцией, если данных чертовски много.

Теперь, если вам нужно проверить, какое ключевое слово встречается во всех операторах, просто используйте словарь поиска.

Предположим, теперь вам нужно проверить, во всех операторах содержится имя ключевого слова, просто выполните поиск в словаре, и вы получите все индексы.

Эта логика называется обратным индексированием и используется lucene, которая используется solr, elasticsearch внутренне.

Комментарии:

1. это возможно, только если записей меньше и в операторах ограниченное количество слов. в противном случае это само по себе займет много времени, а затем поиск ненужных слов, таких как «is», «the», «of» и т.д., Также будет обременительным.

Ответ №5:

Вам нужно это https://en.wikipedia.org/wiki/Aho–Corasick_algorithm Найдите строку в другой строке, это не бесплатно. Более простой способ

 keywords = ['name', 'class', 'school', 'address']

statements = ['name is hello', 'name is not hello', 'school is hello', 'address is hello']
from collection import defaultdict
word2statements = defaultdict(list)
for statement in statements :
    for word in set(statement.split()):
        word2statements[word].append(statement)

for keyword in keywords:
    word2statements[keyword]
  

Комментарии:

1. Сложность по-прежнему равна o (n ^ 2)

2. O (количество слов в операторах len (ключевые слова))