hashmap.get () == оператор, возвращающий false - PullRequest
0 голосов
/ 27 декабря 2018

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

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

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

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

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

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

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

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

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

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

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

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

Формат вывода

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

Пример ввода

8 UDDDUDUU

Пример ввода

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

Ответы [ 5 ]

0 голосов
/ 27 декабря 2018
  1. Решение 1. Если вы должны использовать HashMap, похоже, что итерация в HashMap является проблемой.Ниже ссылка на то, как это сделать.В процессе итерации выстраивайте свою логику для подсчета холмов и долин Как эффективно выполнять итерации по каждой записи на карте Java? .

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

0 голосов
/ 27 декабря 2018

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

Поскольку ваш вопрос ...returning false for big numbers, can someone tell me why?

Вот причина.

Есть несколько вещей, которые вам необходимо понять

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

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

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

Чтобы сравнить примитивную переменную, вы должны использовать ==

Для ссылочного типа сама переменная является «указателем».В Java есть классы Wrapper для примитивов.Например, 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 doc:

public static Integer valueOf (int i)

Возвращает экземпляр Integer, представляющий указанное значение типа int.Если новый экземпляр Integer не требуется, этот метод обычно следует использовать в предпочтении перед конструктором Integer (int), поскольку этот метод, вероятно, даст значительно лучшую производительность пространства и времени за счет кэширования часто запрашиваемых значений. Этот метод всегда будет кэшировать значения в диапазоне от -128 до 127 включительно и может кэшировать другие значения вне этого диапазона.

Поскольку он кэширует оболочки, поэтому, есливы делаете 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
}        
0 голосов
/ 27 декабря 2018

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

0 голосов
/ 27 декабря 2018

для сравнения класса обертки нужно использовать .equals.можно использовать Objects.equals :

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

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

if(java.util.Objects.equals(map.get('D'), map.get('U'))){
   sea = true;
}
0 голосов
/ 27 декабря 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...