Уменьшение временной сложности в цикле forEach

#javascript #arrays #time-complexity #big-o

#javascript #массивы #временная сложность #big-o

Вопрос:

Я создаю простую игру hangman с использованием Javascript и хотел узнать, каким будет наилучший способ оптимизации моего кода.

 const Hangman = function (word, remainingGuesses) {
  this.word = word.toLowerCase().split("");
  this.remainingGuesses = remainingGuesses;
  this.guessedLetters = [];
};

Hangman.prototype.getPuzzle = function () {
  let puzzle = "";
  this.word.forEach((char) => {
    this.guessedLetters.includes(char) || char === " "
      ? (puzzle  = char)
      : (puzzle  = "*");
  });
  return puzzle;
};
 

На данный момент, как вы можете видеть из приведенного выше кода, я выполняю forEach цикл for this.word , а затем внутри forEach цикла, который я использую .includes() , чтобы определить, было ли угадано слово, если нет, то установите значение char * равным .

На данный момент я считаю, что временная сложность из O(n2) -за includes() внутренней forEach части, что было бы лучшим способом переписать getPuzzle() функцию?

Ответ №1:

Используйте Set for guessedLetters для постоянного поиска по времени:

 const Hangman = function (word, remainingGuesses) {
  this.word = word.toLowerCase().split("");
  this.remainingGuesses = remainingGuesses;
  this.guessedLetters = new Set(); // this is a Set now
};

Hangman.prototype.getPuzzle = function () {
  let puzzle = "";
  this.word.forEach((char) => {
    // use Set.has instead of Array.includes
    this.guessedLetters.has(char) || char === " "
      ? (puzzle  = char)
      : (puzzle  = "*");
  });
  return puzzle;
};
 

Вы можете добавить новую угаданную букву с this.guessedLetters.add(char) помощью .

Комментарии:

1. Да, использование Set или hash — это правильный путь для более быстрого поиска (в отличие от повторяющихся линейных поисков по массиву). НО, поскольку строки неизменяемы, ваш цикл forEach ПО-ПРЕЖНЕМУ выполняет много ненужной работы; при каждом использовании ‘ =’ приходится заново создавать всю строку заново. Чтобы избежать этого, измените переменную puzzle на массив, измените «(puzzle = char)» на «puzzle.push(char)» (то же самое для «*») и верните puzzle.join(«). Это означает, что вы создаете строку только один раз.

2. Очень интересное и чистое решение с набором. Однако у меня есть один вопрос: не является ли простой объект (сопоставление ключа и значения) еще быстрее? Объект будет выглядеть примерно так: {‘a’: ‘a’, ‘b’: ‘b’ }, где ‘a’ и ‘b’ — это угаданные буквы.

3. Наборы, как правило, быстрее, чем объекты.

4. Мне стало любопытно об этом сравнении, потому что я всегда думал, что объекты быстрее. Итак, я нашел тест, который говорит, что объекты намного быстрее, чем наборы и карты. К сожалению, я не смог найти, какие операции были использованы для получения этих результатов. measurethat.net/Benchmarks/Show/5364/0/set-vs-object-vs-map