Какова временная сложность HashMap.containsValue() в java?
Мне была задана проблема в сложности O(n)
:
"Учитывая список чисел и число x. Найдите, есть ли в списке два числа, которые содержат до x?"
И это мое решение:
public class SumMatchResult {
public static void main(String[] args){
int[] numberList = {6,1,8,7,4,6};
int requiredSum = 8;
boolean isSumPresent = checkSumPresentHash(numberList,requiredSum);
if(isSumPresent) {
System.out.println("Numbers exist");
}else {
System.out.println("Numbers donot exist");
}
}
private static boolean checkSumPresentHash(int[] numberList, int requiredSum) {
Map<Integer, Integer> m = new HashMap<Integer,Integer>();
int count = 0;
for(int i=0;i<numberList.length;i++){
m.put(i, numberList[i]);
}
for(int i=0;i<numberList.length;i++){
if(m.containsValue(requiredSum - numberList[i])){
count++;
}
}
if(count>1){
return true;
}
return false;
}
}
Я использую HashMap.containsValue()
вместо использования HashSet.contains()
, который, безусловно, имеет сложность O(1)
, потому что мне приходится учитывать сценарий, в котором мой ввод может содержать одинаковые значения. Например, в приведенном выше случае у меня может быть установлен набор входных значений {3,6,4,4,7}
для sum 8
, который должен возвращать true
.
Моя сложная временная сложность решения зависит от сложности метода HashMap.containsValue()
. Прошу прояснить временную сложность метода containsValue()
и предложить мне, если есть лучшее решение для вышеупомянутой проблемы с точки зрения временной сложности. Спасибо.
Ответы
Ответ 1
Чтобы ответить на вопрос в названии - как упоминалось другими, containsValue
- O (n), потому что без ключа он не знает, где он находится, и алгоритм должен пройти все значения, хранящиеся в карта.
Чтобы ответить на вопрос в теле вашего вопроса - о том, как его решить, просто подумайте, действительно ли вам нужна общая карта, которая может подсчитать, сколько экземпляров вы видели для каждого номера. Я имею в виду, единственный раз, когда вам было бы интересно, если бы появилось больше одного вида числа, когда оно х /2, правильно? Это пахнет угловым делом для меня. Просто добавьте тест, который проверяет этот угловой регистр - что-то вроде вложения if (numberList[i] == requiredSum/2) half++
во время цикла установки-построения, а затем if (requiredSum % 2 == 0 && half == 2) return true
после него (см. Другие варианты ниже).
Затем вы можете просто перебирать множество и для каждого элемента проверять, появляется ли requiredSum-item
в наборе.
Подводя итог (с ранним выходом, когда это возможно):
Set<Integer> seen = new HashSet<Integer>();
boolean halfSeen = false;
for (int num : numberList) {
if (num == requiredSum/2 && requiredSum % 2 == 0) {
if (halfSeen) return true;
halfSeen = true;
} else {
seen.add(num);
}
}
for (int num : seen) {
if (seen.contains(requiredSum - num)) return true;
}
return false;
Ответ 2
HashMap по существу является хранилищем ключей, который может обращаться к ним со сложностью O (1). Однако при проверке значения ничего не может сделать HashMap, но проверить все значения и посмотреть, соответствуют ли они тем, которые вы ищете. Следовательно, сложность O (n), где n - количество элементов в HashMap.
В другом примечании: вы просматриваете примитивные значения (int) в коллекции своего типа в виде бокса (Integer). Это означает, что каждый раз, когда вы вызываете метод на HashMap, Java должен указывать вам примитивные значения: http://docs.oracle.com/javase/1.5.0/docs/guide/language/autoboxing.html
Ответ 3
Сложность HashMap.containsValue - это O (n). Но n - это не точно размер карты, а размер хэш-таблицы, потому что containsValue проходит через все элементы таблицы, даже если размер карты равен 0.
Предположим, мы создали пустую карту с начальной емкостью = 1024. containsValue должен будет пройти через массив хеш-таблиц 1024 элементов:
public boolean containsValue(Object value) {
if (value == null)
return containsNullValue();
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (Entry e = tab[i] ; e != null ; e = e.next)
if (value.equals(e.value))
return true;
return false;
}