В недавней статье мы рассматривали такую структура данных как стек. Если вы не знаете что такое стек, то обязательно перейдите по ссылке и почитайте, потому что сегодня мы разберем решение одной интересной задачи с сайта codeforces.com с использованием реализованного ранее нами стека. Вот условие задачи:
В автобусе характеров есть n рядов сидений, в каждом по 2 места. В -м ряду ширина обоих сидений равна сантиметров. Все числа i различны.
Изначально автобус пустой. На каждой из 2n остановок в автобус садится ровно один человек одного из двух характеров:
- интроверт всегда выбирает ряд, где оба места свободны, при этом из таких рядов он выбирает ряд с самыми узкими сидениями, и занимает одно место;
- экстраверт всегда выбирает ряд, где уже сидит один человек (интроверт), при этом из таких рядов он выбирает ряд с самыми широкими сидениями, и занимает оставшееся в выбранном ряду место.
Вам дана ширина сидений в каждом ряду, а также порядок, в котором входили пассажиры. Определите, на какой ряд сядет каждый из пассажиров.
В первой строке следует целое число n () — количество рядов сидений в автобусе.
Во второй строке следует последовательность целых чисел (, где равно ширине каждого из двух сидений в -м ряду. Гарантируется, что все различны.
В третьей строке следует строка длины 2n, состоящая из символов «0» и «1» — описание порядка, в котором пассажиры заходят в автобус. Если -й символ строки равен «0», то на -й остановке в автобус зашел интроверт. Если -й символ строки равен «1», то на -й остановке в автобус зашел экстраверт. Гарантируется, что интровертов и экстравертов, которые зашли в автобус, поровну (то есть по n), и для каждого экстраверта всегда найдется подходящий ряд.
Выведите n целых чисел — номера рядов, в которые сели пассажиры. Номера рядов для пассажиров должны быть выведены в том же порядке, в котором пассажиры заданы во входных данных.
1 2 3 |
2 3 1 0011 |
1 |
2 1 1 2 |
Описание алгоритма решения задачи
Из условия задачи можно заметить следующую закономерность: каждый новый экстраверт сядет к интроверту, который сидит на сиденье с самой большой шириной. Значит, что могут быть еще интроверты в автобусе, и гарантировано что ширина их сидений меньше. Это типичный стек. Идея для решения в следующем. Пойдем по порядку входных данных. Сначала мы получаем число n и создаем объект класса Stack. Далее ширины сидений мы запишем в map по принципу (номер ряда -> ширина). Затем нам необходимо отсортировать ее (мапу) по значению и последовательно сложить в стек номера рядов, причем на самом верху будет номер с наименьшей шириной. Последовательность из 0 и 1 (интровертов и экстравертов, которые будут заходить в автобус мы сложим в массив. Рассмотрим пример, в котором n=3, ширины рядов: 8 4 5, а последовательность людей: 0 0 1 1 0 1. Предложенная раскладка данных будет выглядеть так:

Последовательность захода людей в автобус
Отлично. Теперь нам необходимо создать второй стек, который будет тоже иметь размерность n, но будет пустым. После мы начинаем последовательно извлекать из массива людей (элементы 0 и 1) и проводить два типа операций в зависимости от того, кто зашел интроверт или экстраверт:
-
- Зашел интроверт 0. Так как зашел интроверт и нам известно, что он сядет на свободный ряд с самой минимальной шириной. Значит мы выводим на консоль и извлекаем элемент из стека с ширинами, и кладем его в пустой, заранее подготовленный стек.
- Зашел экстраверт 1. Экстраверт сядет к интроверту, причем к тому, который сидит на максимально широком ряду. Из второго стека, мы извлекаем элемент и выводим его на консоль. Это справедливо, потому что если заходили интроверты, то ряд с максимальной шириной окажется на верху стека. Соответственно, если зайдет еще один экстраверт, то он так же сядет с интровертом, у которого ширина ряда максимальная в силу принципа работы нашего стека.
Реализация алгоритма на языке Java представлена ниже:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263import java.util.*;public class Solution {static class Stack {private int size; // Размер стекаprivate int top; // индекс вершиныprivate int[] stack; // сам стекpublic Stack(int size) { // конструктовthis.size = size;top = -1; // -1 потому что стек пустstack = new int[size]; // иницилизазция}public int pop() { // извлечение элементаreturn stack[top--];}public int peek() { // получение элементаreturn stack[top];}public void push(int a) { // вставка элементаstack[++top] = a;}public boolean isEmpty() { // проверка путой ли стекreturn (top == -1);}public boolean isFull() { // проверка полон ли стекreturn (top == size - 1);}}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();Map<Integer, Integer> map = new HashMap<>();Stack stackSeatWidths = new Stack(n); // создаем стек где будут номера ширин рядовfor (int i = 1; i <= n; i++) {map.put(i, scanner.nextInt()); // заполняем map с ширинами, где ключ - номер ряда}map.entrySet().stream() // с помощью stream API сортируем map по значениям.sorted(Map.Entry.<Integer, Integer>comparingByValue().reversed()).forEach(m -> stackSeatWidths.push(m.getKey()));// и складываем в стек упорядоченные по ширине номера сиденийString str = scanner.next();char[] b = str.toCharArray();Stack stackSeatWidths2 = new Stack(b.length); // создаем второй стек для номеров ширинfor (int i = 0; i < n * 2; i++) {if (b[i] == '0') { // если интроверт выводим значение из стека местSystem.out.print(stackSeatWidths.peek() + " ");stackSeatWidths2.push(stackSeatWidths.pop()); //кладем вв второй стек}if (b[i] == '1') // если экстраверт, выводим значение из второго стекаSystem.out.print(stackSeatWidths2.pop() + " ");}}}