Как восстановить приоритет PriorityQueue до его начального состояния перед вызовом метода?

Я делаю проблему с практикой Практика IT Kth Smallest

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

Мое псевдо-мышление более высокого уровня состоит в том, что, поскольку PriorityQueue уже действует как минимальная куча, от Java PriorityQueue, все, что мне действительно нужно делать ( мой алгоритм):

  • Удалите k элементов из PriorityQueue

  • Сохраните k-е наименьшее значение как локальную переменную

  • Нажмите удаленные элементы k на стек (Stack, чтобы я мог добавлять элементы в том же порядке)

  • Попасть все элементы из Stack и снова добавить их в PriorityQueue

  • Возвращает k-е наименьшее значение

Вот код, чтобы сделать все это:

public int kthSmallest(PriorityQueue<Integer> pQ, int k) {
    if(k <= 0 || k > pQ.size()) {
           throw new IllegalArgumentException();
    } else {
         Stack<Integer> aux = new Stack<Integer>();
         int kThSmallest = -1;
         for(int c=0;c<k;c++){
               int element = pQ.remove();
               if(c == k-1) 
                   kThSmallest = element;
               aux.push(element);
          }
          while(!aux.isEmpty())
              pQ.add(aux.pop());
         return kThSmallest;
      }    
}

Когда я запускаю программу, я получаю все правильные выходы в терминах k-го наименьшего числа, но я не могу восстановить состояние моего PriorityQueue. Например, при передаче в PriorityQueue:

[-3, 9, 17, 22, 42, 81] with a k of 3

... мой алгоритм дает правильный результат 17, но он меняет состояние PriorityQueue на [-3, 17, 9, 81, 22, 42], что неожиданно.

Я думал о создании копии PriorityQueue, но это нарушает одно из условий: "вы можете использовать один стек или очередь в качестве вспомогательной структуры данных".

Как я могу восстановить состояние PriorityQueue?

Ответ 1

В вашей реализации необходимо скорректировать две вещи. Во-первых, в качестве дополнительной структуры данных вы должны использовать очередь, а не стек. Толкание элементов в стек и последующее отключение их приведет к тому, что они будут добавлены обратно в очередь приоритетов в обратном порядке. Если они выходят из очереди приоритетов как 1, 2, 3, они будут добавлены обратно в очередь приоритетов как 3, 2, 1. Это связано с тем, что стеки представляют собой структуру данных LIFO (Last in, first out). Вы хотите использовать очередь в качестве своей вспомогательной структуры данных, потому что это структура данных FIFO (First in, first out), поэтому она сохранит тот же порядок.

Во-вторых, вы вытаскиваете только первые k элементов из очереди priorty. Я бы рекомендовал осушить всю очередь, так что вы добавляете все элементы обратно в очередь в том порядке, в котором они выходили, а не только в некоторых.

Другими словами, я бы скорректировал вашу программу следующим образом:

public int kthSmallest(PriorityQueue<Integer> pQ, int k) {
    if(k <= 0 || k > pQ.size()) {
           throw new IllegalArgumentException();
    } else {
         Queue<Integer> aux = new ArrayDeque<Integer>();
         int kThSmallest = -1;
         for(int c=0;c<pQ.size();c++){
               Integer element = pQ.remove();
               if(c == k-1) 
                   kThSmallest = element;
               aux.add(element);
          }
          while(!aux.isEmpty())
              pQ.add(aux.remove());
         return kThSmallest;
      }
}

Примечание. Я изменил переменную "element" в вашей программе с типа int на Integer. Это не важно для правильности вашей программы, но это хорошая привычка уделять внимание авто-боксу. Общие типы, такие как коллекции, используют целые числа в штучной упаковке. Это объект, в котором хранится примитивное целое число. Присвоение целочисленного целого числа типу int требует, чтобы он был распакован, т.е. Вернулся в примитив int. Это не имеет большого значения, за исключением того, что вы снова добавляете это значение обратно в коллекцию. Так как вы распаковали его в примитивный int, его снова нужно вернуть обратно в Integer, и для этого требуется, чтобы система создала объект для его хранения. Поскольку все, что вы делаете со значением, вынимая его и помещая обратно в коллекции, лучше использовать здесь значение Integer, чтобы избежать распаковки и бокса значения, поскольку это действительно не нужно.