Медленный и отстающий javascript [дубликат]

Решение этой проблемы было дано миллион раз в Интернете. Задача называется Задача об изменении монет . Можно найти решения в http://rosettacode.org/wiki/Count_the_coins и математическую модель этого в http://jaqm.ro/issues/volume-5,issue-2/ pdf / patterson_harmel.pdf (или проблема с изменением монеты Google ).

Кстати, решение Scala от Tsagadai интересно. В этом примере получается 1 или 0. В качестве побочного эффекта он перечисляет на консоли все возможные решения. Он отображает решение, но не делает его пригодным для использования каким-либо образом.

Чтобы быть как можно полезнее, код должен возвращать List[List[Int]], чтобы разрешить получать количество решений (длина списка списков), «лучшее» решение (самый короткий список) или все возможные решения.

Вот пример. Это очень неэффективно, но это легко понять.

object Sum extends App {

  def sumCombinations(total: Int, numbers: List[Int]): List[List[Int]] = {

    def add(x: (Int, List[List[Int]]), y: (Int, List[List[Int]])): (Int, List[List[Int]]) = {
      (x._1 + y._1, x._2 ::: y._2)
    }

    def sumCombinations(resultAcc: List[List[Int]], sumAcc: List[Int], total: Int, numbers: List[Int]): (Int, List[List[Int]]) = {
      if (numbers.isEmpty || total < 0) {
        (0, resultAcc)
      } else if (total == 0) {
        (1, sumAcc :: resultAcc)
      } else {
        add(sumCombinations(resultAcc, sumAcc, total, numbers.tail), sumCombinations(resultAcc, numbers.head :: sumAcc, total - numbers.head, numbers))
      }
    }

    sumCombinations(Nil, Nil, total, numbers.sortWith(_ > _))._2
  }

  println(sumCombinations(15, List(1, 2, 5, 10)) mkString "\n")
}

При запуске он отображает:

List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2)
List(1, 1, 1, 1, 1, 2, 2, 2, 2, 2)
List(1, 1, 1, 2, 2, 2, 2, 2, 2)
List(1, 2, 2, 2, 2, 2, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5)
List(1, 1, 1, 1, 1, 1, 1, 1, 2, 5)
List(1, 1, 1, 1, 1, 1, 2, 2, 5)
List(1, 1, 1, 1, 2, 2, 2, 5)
List(1, 1, 2, 2, 2, 2, 5)
List(2, 2, 2, 2, 2, 5)
List(1, 1, 1, 1, 1, 5, 5)
List(1, 1, 1, 2, 5, 5)
List(1, 2, 2, 5, 5)
List(5, 5, 5)
List(1, 1, 1, 1, 1, 10)
List(1, 1, 1, 2, 10)
List(1, 2, 2, 10)
List(5, 10)

Функция sumCombinations() может использоваться сама по себе и результат может быть дополнительно проанализирован, чтобы отобразить «лучшее» решение (самый короткий список) или количество решений (количество списков).

Обратите внимание, что даже так, требования могут быть не полностью доволен. Может случиться так, что порядок каждого списка в решении будет значительным. В таком случае каждый список должен дублироваться столько раз, сколько есть комбинация его элементов. Или нас могут интересовать только разные комбинации.

Например, мы могли бы подумать, что List(5, 10) должен дать две комбинации: List(5, 10) и List(10, 5). Для List(5, 5, 5) он может давать только три комбинации или один, в зависимости от требований. Для целых чисел три перестановки эквивалентны, но если мы имеем дело с монетами, например, в «проблеме смены монет», это не так.

Также не указано в требованиях, является ли вопрос о том, (или монету) можно использовать только один или несколько раз. Мы могли бы (и должны!) Обобщить проблему на список списков вхождений каждого числа. Это переводит в реальной жизни в «каковы возможные способы сделать определенную сумму денег с помощью набора монет (а не набора значений монет)». Первоначальная проблема - только частный случай этого, где у нас столько же вхождений каждой монеты, сколько необходимо, чтобы сделать общую сумму с каждым значением одной монеты.

1
задан Luke 1 May 2016 в 07:30
поделиться

1 ответ

[I] .. открыл возможность создания действительно плохой «утечки памяти»

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

Проблема возникает, когда вы постоянно сохраняете стоп состояния без восстановления.

Этого следует ожидать.

Как вы можете удалить или удалить стек состояния для контекста canvas?

Единственный способ - либо восстановить все сохраненные состояния, либо сбросить контекст, установив некоторый размер в элемент холста (т.е. canvas.width = canvas.width).

Также безопасно называть restore() больше раз, чем save() (в этом случае он просто возвращается без каких-либо действий), чтобы вы могли теоретически запустить его через цикл из n числа итераций. Это последнее будет больше в категории плохой практики.

Но с учетом сказанного: если есть несоответствие в числах сохранения и восстановления, когда оно должно быть равным, обычно указывает на проблему где-то еще в код.

Вот пример того, как отслеживать количество вызовов сохранения / восстановления -

// NOTE: this code needs to run before a canvas context is created
CanvasRenderingContext2D.prototype.__save = CanvasRenderingContext2D.prototype.save;
CanvasRenderingContext2D.prototype.__restore = CanvasRenderingContext2D.prototype.restore;

// Our patch vectors
CanvasRenderingContext2D.prototype.__tracker = 0;
CanvasRenderingContext2D.prototype.save = function() {
  this.__tracker++;
  console.log("Track save:", this.__tracker);
  this.__save() 
}

CanvasRenderingContext2D.prototype.restore = function() {
  this.__tracker--;
  console.log("Track restore:", this.__tracker);
  this.__restore() 
}

// custom method to dump status
CanvasRenderingContext2D.prototype.trackstat = function() {
  if (this.__tracker)
    console.warn("Track stat:", this.__tracker);
  else
    console.log("Track stat: OK");
}

var ctx = document.createElement("canvas").getContext("2d");
ctx.save();                     // do a couple of save()s
ctx.save();
ctx.restore();                  // single restore()
ctx.trackstat();                // should report mismatch of 1
ctx.restore();                  // last restore()
ctx.trackstat();                // should report OK

1
ответ дан epistemex 17 August 2018 в 14:46
поделиться
  • 1
    «мы должны убедиться, что мы отслеживаем количество нажатий (или сохраняет), а также всплывает (восстанавливается) сами». & lt; - Это, безусловно, лучшая практика, никаких аргументов нет! Но мы могли бы сделать ошибку или использовать код, написанный кем-то, кто был не так осторожен. В идеале я надеялся найти способ обнаружить эту проблему и отменить ее, если она обнаружена. Если это верно - «У нас нет доступа к указателю стека», - тогда наши варианты ограничены. – Luke 5 May 2016 в 21:55
  • 2
    Доступ к @Luke действительно ограничен. Вы можете & quot; patch & quot; вызовы сохранить временный трек для целей отладки. Я добавлю пример о том, как это сделать, но это, конечно, как снятие гриппа за боль в носке. Проблема указывает на проблемы с дизайном. – epistemex 6 May 2016 в 00:03
  • 3
    Нет, это действительно утечка памяти. Даже технически! – Ry-♦ 17 January 2018 в 23:39
  • 4
    @Ryan нет, утечка «потеряна». Память. Хранение на памяти, которую вы можете освободить в любое время, - это просто плохая практика, а не утечка (и очень сложно произвести фактические утечки памяти на языке, таком как JS, если нет преднамеренной попытки или браузера ошибка). – epistemex 17 January 2018 в 23:55
  • 5
    @ K3N: утечка - это память, которая не освобождается, когда она больше не используется. Это точно соответствует счету. Представление, что трудно сделать утечки памяти в JS, просто ... неправильно. – Ry-♦ 18 January 2018 в 00:10
Другие вопросы по тегам:

Похожие вопросы: