Hashmap.get () == оператор, возвращающий false

Я работаю над следующей проблемой:

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

Для каждого шага, который он сделал, он отмечал, был ли это шаг в гору, U или вниз, D. Походы Гэри начинаются и заканчиваются на уровне моря, и каждый шаг вверх или вниз представляет собой изменение высоты на 1 единицу. Мы определяем следующие термины:

Гора - это последовательность последовательных шагов над уровнем моря, начиная с шага вверх от уровня моря и заканчивая шагом вниз к уровню моря.

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

Например, если путь Гэри s = [DDUUUUDD], он сначала входит в долину глубиной 2 единицы. Затем он взбирается на гору высотой 2 единицы. Наконец он возвращается на уровень моря и заканчивает поход.

Описание функции

Завершите функцию countingValleys в редакторе ниже. Он должен возвращать целое число, обозначающее количество долин, пройденных Гэри.

countingValleys имеет следующие параметры:

n: количество шагов, которые делает Гэри

s: строка, описывающая его путь Формат ввода

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

Выходной формат

Выведите единственное целое число, обозначающее количество долин, через которые прошел Гэри во время похода.

Пример ввода

8 УДДДУДУУ

Пример вывода

1

Ниже моя реализация на java. Это работает для небольших тестовых случаев, но не для больших.

static int countingValleys(int n, String s) {


  //Use a hashmap to keep track of the number of moves.
  HashMap<Character,Integer> map = new HashMap();

  boolean sea = true;//check if we are at sea level

  //if both D and U have the same total no, we are at sea level.
  map.put('D',0);
  map.put('U',0);

  int valleys = 0;//count num of valleys

  for(int i = 0; i < n; i++){
      char key = s.charAt(i);

      //check if we are at sea level
      if (map.get('D') == map.get('U')){//<--PROBLEM
          sea = true;
      }
      else
          sea = false;

      if (sea == true && key == 'D'){//if we are at sea level and our next key is D, we have a valley

          valleys += 1;
      }

      map.put(key,map.get(key) + 1);//add move and update our hashmap   
  }

  return valleys;

}

Проблема, похоже, в «if (map.get ('D') == map.get ('U'))», кажется, что она возвращает false для больших чисел, может кто-нибудь сказать мне, почему? Это работает, если я назначаю каждый map.get () переменной и вместо этого сравниваю переменные.

Я также написал то же самое в javascript, используя тип «new Object ()», и он прошел все тестовые примеры, но он не работает в java с hashmap, почему?

ссылка на оригинальную задачу - https://www.hackerrank.com/challenges/counting-valleys/problem?h_l=interview&playlist_slugs%5B%5D=interview-preparation-kit&playlist_slugs%5B%5D=warmup

используйте equals метод if (map.get('D').equals(map.get('U')))

Deadpool 27.12.2018 04:27
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
219
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Во-первых, не используйте '=='. Использование .equals для всех классов расширяет Object.

Совет на самом деле неверен. Есть случаи, когда == предпочтительнее equals() для эталонного типа. Сравнение Enum является одним из примеров того, что использование == лучше, чем equals()

Adrian Shum 27.12.2018 07:10

Он не сравнивает ссылки и перечисления.

Crutch Master 27.12.2018 07:19

Да, я знаю, но в вашем ответе указано «Используйте .equals для всех классов расширяет Object», что в целом неверно.

Adrian Shum 27.12.2018 07:21

для сравнения содержимого классов-оболочек (Integer, Float, Long, Double) используйте .equals (). «==» сравнивает ссылки обоих объектов. Ссылки могут быть разными, даже если оба содержат одинаковое содержание. Однако вы можете использовать "==" при сравнении типов ценность, таких как int, float, long, double.

для сравнения класса оболочки нужно использовать .equals. можно использовать Объекты. Равные:

java.util.Objects.equals(firstInteger, secondInteger);

для случая выше:

if (java.util.Objects.equals(map.get('D'), map.get('U'))){
   sea = true;
}
Ответ принят как подходящий

Во-первых, как упоминалось в другом ответе, в этом случае используйте .equals() вместо ==. Еще лучший подход - вам даже не нужно использовать Map. Достаточно одного целого числа.

В качестве вашего вопроса ...returning false for big numbers, can someone tell me why?

Вот причина.

Вам нужно понять несколько вещей

1. Типы переменных

Во-первых, вам нужно знать, что в Java есть два типа переменных: примитивные и ссылочные.

Целое число обычно является примитивом, поэтому сама переменная является целочисленным значением: int a = 1234;: сам a имеет значение 1234.

Для сравнения примитивной переменной следует использовать ==.

Для ссылочного типа переменная сама по себе является «указателем». В Java есть классы-оболочки для примитивов. Например, Integer - это оболочка для int. Итак, в Integer a = new Integer(1234);a не содержит значения 1234. Это указатель, указывающий на ссылку на объект Integer. Использование == для переменных ссылочного типа не сравнивает содержимое, а только проверяет, совпадает ли значение указателя (т. Е. Проверяет, указывают ли они на один и тот же экземпляр объекта)

2. Автобокс

Начиная с Java 1.5 (iirc), существует функция, называемая автоматическим боксом (и распаковкой), которая упрощает программисту преобразование между примитивными типами и их соответствующей оболочкой.

Раньше вам нужно было сделать что-то вроде этого:

int a = 1234;
Integer intWrapper = new Integer(a);

int b = intWrapper.intValue();

С автобоксингом вам просто нужно написать:

int a = 1234;
Integer intWrapper = a;
int b = intWrapper;

И компилятор собирается преобразовать его в:

int a = 1234;
Integer intWrapper = Integer.valueOf(a);
int b = intWrapper.intValue();

Все идет нормально?

Окончательный ответ

Итак, причина, по которой ваш код работает с небольшим числом: Integer.valueOf() кэширует часто используемое значение. Из документа API:

public static Integer valueOf(int i)

Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.

Поскольку он кэширует оболочки, поэтому, если вы выполняете map.put(key,map.get(key) + 1), результатом get(key) + 1, который является int, при преобразовании в Integer и, если это небольшое число, будет тот же экземпляр Integer для того же значения int. Это означает, что == по-прежнему работает (поскольку переменные указывают на тот же Integer). Однако, если это не кэшируемое число, каждый вызов будет отдельным экземпляром, и == не будет работать (поскольку переменные указывают на разные экземпляры Integer, хотя значения в экземплярах Integer одинаковы)


Предложение к вашему алгоритму, хотя и не по теме:

Ваша логика слишком сложна. Его можно значительно упростить до (псевдокода):

countValley(String s) {
    currentLevel = 0
    valleyCount = 0
    for (step in s) {
        if step == 'U' {
            ++currentLevel;
            if (currentLevel == 0) {  // returning to sea level
                ++valleyCount
            }
        } else if step == 'D' {
            --currentLevel;
        }
    }
    return valleyCount
}        

@chacha, если он отвечает на ваш вопрос, примите его. Спасибо

Adrian Shum 27.12.2018 07:08
  1. Решение 1. Если вы должны использовать HashMap, похоже, проблема заключается в итерации в HashMap. Ниже ссылка на то, как это сделать. По мере повторения выстраивайте свою логику для подсчета холмов и долин. Как эффективно перебирать каждую запись на карте Java?.

Решение 2. Используйте массив вместо HashMap. После его создания найдите последовательности D и так далее.

Другие вопросы по теме