Union-Find Leetcode вопрос превышает лимит времени

Я решаю эту проблему на Leetcode https://leetcode.com/problems/sentence-similarity-ii/description/ это включает в себя реализацию алгоритма объединения-поиска, чтобы выяснить, являются ли два предложения одинаковыми или нет, задан список пар, представляющих похожие слова. Я реализовал ранжированное объединение-поиск, где я отслеживаю размер каждого подмножества и присоединяю меньшее поддерево к большему, но по какой-то причине код все еще превышает ограничение по времени. Может кто-то указать мне, что я делаю неправильно? Как это можно оптимизировать дальше. Я видел, что другие принятые решения использовали такой же ранжированный алгоритм поиска объединения.

Вот код:

    string root(map<string, string> dict, string element) {
if(dict[element] == element)
return element;
return root(dict, dict[element]);
}
bool areSentencesSimilarTwo(vector<string>& words1, vector<string>& words2, vector<pair<string, string>> pairs) {
if(words1.size() != words2.size()) return false;
std::map<string, string> dict;
std::map<string, int> sizes;
for(auto pair: pairs) {
if(dict.find(pair.first) == dict.end()) {
dict[pair.first] = pair.first;
sizes[pair.first] = 1;
}
if(dict.find(pair.second) == dict.end()) {
dict[pair.second] = pair.second;
sizes[pair.second] = 1;
}

auto firstRoot = root(dict, pair.first);
auto secondRoot = root(dict, pair.second);
if(sizes[firstRoot] < sizes[secondRoot]) {
dict[firstRoot] = secondRoot;
sizes[firstRoot] += sizes[secondRoot];
}
else {
dict[secondRoot] = firstRoot;
sizes[secondRoot] += sizes[firstRoot];
}
}for(int i = 0; i < words1.size(); i++) {
if(words1[i] == words2[i]) {
continue;
}
else if(root(dict, words1[i]) != root(dict, words2[i])) {
return false;
}
}
return true;
}

Спасибо!

0

Решение

Ваша профсоюзная находка сломана в отношении сложности. Пожалуйста, прочитайте Википедия: Несвязанная-заданная структура данных.

Чтобы union-find имел сложность, близкую к O (1), он должен использовать сжатие путей. Для этого ваш root Метод должен:

  1. Получить dict по ссылке, так что он может изменить его.
  2. Сделайте уплотнение пути ко всем элементам на пути, чтобы они указывали на корень.

Без уплотнения у вас будет сложность O (log N) для root(), что может быть хорошо. Но для этого вы должны исправить это так, чтобы root() получает dict по ссылке, а не по значению. Переходя dict по стоимости стоит O (N).

Дело в том, что dict является std::map делает любой запрос стоимостью O (log N) вместо O (1). std::unordered_map стоит O (1), но на практике для N < 1000, std::map быстрее. Кроме того, даже если std::unordered_map используется, хэширование строки стоит O (len (str)).

Если объем данных велик, а производительность все еще низкая, вы можете выиграть от работы с индексами в pairs вместо строк, и запустите union-find с индексами в vector<int>, Это подвержено ошибкам, так как вы должны правильно обрабатывать дубликаты строк.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]