Какова временная сложность 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;
}