Вертикальный заказ обход двоичного дерева
Ссылка на вопрос летакода
В последнее время я шлифовал лецкод и решил записать некоторые из моих мыслей в этом блоге. Это оба, чтобы помочь мне оглянуться назад на то, о чем я работал, а также помогите другим видеть, как можно подумать о проблемах.
Тем не менее, поскольку многие люди публикуют свои собственные решения в раздел дискуссий IETCODE, я не обязательно буду публиковать оптимальное решение.
Вопрос
( Копия вставлена из лецкода)
Учитывая двоичное дерево, верните вертикальный порядок обходных значений узлов.
Для каждого узла в положении (X, Y) его левые и правые дети соответственно будут на позициях (x – 1, y-1) и (x + 1, y-1).
Запуск вертикальной линии от x = -infinity до x = + бесконечности, всякий раз, когда вертикальная линия касается некоторых узлов, мы сообщаем о значениях узлов в порядке сверху вниз (уменьшающиеся координаты Y).
Если два узла имеют одинаковое положение, то значение узла, которое сообщается, что сначала – это значение меньше.
Верните список непустых отчетов в порядке X координаты. Каждый отчет будет иметь список значений узлов.
Пример 1:
Input: [3,9,20,null,null,15,7] Output: [[9],[3,15],[20],[7]]
Объяснение: Без потери общности мы можем предположить, что корневой узел находится в положении (0, 0): Затем узел со значением 9 происходит в положении (-1, -1); Узлы со значениями 3 и 15 происходят на позициях (0, 0) и (0, -2);
Узел со значением 20 встречается в положении (1, -1); Узел со значением 7 встречается в положении (2, -2).
Пример 2:
Input: [1,2,3,4,5,6,7] Output: [[4],[2],[1,5,6],[3],[7]]
Объяснение: Узел со значением 5 и узел со значением 6 имеют одинаковое положение в соответствии с заданной схемой. Однако в отчете «[1,5,6]» значение узла 5 приходит первым с 5 меньше 6.
Примечания:
- Дерево будет иметь от 1 до 1000 узлов.
- Значение каждого узла будет от 0 до 1000.
Мой подход (ES)
Я не буду преодолевать весь код для всех попыток, но я объясню свой подход (ы) качественно.
Попытка 1 – DFS или BFS
(Представлено – принято)
Основываясь на подробных инструкциях, я понимаю, что каждый узел будет иметь собственную координату X и Y (относительно корневого узла). С этим пониманием я использовал первый поиск глубины, чтобы найти бинарное дерево и добавить каждый узел в структуру данных. Я использовал объект JavaScript, который имеет характеристики хэш таблицы, чтобы держать данные о каждом узле.
Поскольку нам нужно вернуть структуру данных, которая сортирует узлы по значению x, я решил отсортировать их по значению x, когда добавляю их в контейнер.
Я хотел, чтобы мой контейнер выглядел что-то подобное, после того, как он был заполнен (используя примерные значения 1):
const xCoordMap = { "-1": [{val:9, y:-1}], "0": [{val:3, y:0}, {val:15, y:-2}], "1": [{val:20, y:1}], "2": [{val:7, y:2}] }
Первоначально я пытался использовать широкий поиск первого поиска, потому что этот алгоритм поиска ищет все узлы того же уровня Y, последовательно. Однако, когда есть галстук в Y значение Y, вопрос хочет, чтобы значение более низкого узла было установлено первым. Поэтому я закончил запись значений Y, чтобы обнаружить связи, а затем сначала отсортировала их самым высоким значением y, а затем самым низким значением (если значения Y привязаны).
Представляемый код JavaScript:
var verticalTraversal = function(root) { // dfs or bfs but calculate the coordinates while running it // using bfs we won't have to use the Y values to sort (?) // left goes to X-1, Y-1, right goes to X+1, Y-1 let stack = [{...root, x: 0, y:0}]; let xCoordMap = {} const addNode = (val, x, y) => { // if the key, 'x', already exists, push it // if it doesn't, make a new array if (xCoordMap[`${x}`]) { xCoordMap[`${x}`].push({val, y}); } else { xCoordMap[`${x}`] = [{val, y}]; } } while (stack.length > 0) { const currNode = stack.pop(); addNode(currNode.val, currNode.x, currNode.y); if (currNode.left) { stack.push({...currNode.left, x: currNode.x - 1, y: currNode.y - 1}); } if (currNode.right) { stack.push({...currNode.right, x: currNode.x + 1, y: currNode.y - 1}); } } // we have an object with numbered keys and arrays of values const sortedKeys = Object.keys(xCoordMap).sort((a,b) => Number(a) - Number(b)); const vertArrays = sortedKeys.map(key => { // sort the array then return it with only vals, not x and y // sort by y first, then by value if y's are the same xCoordMap[key].sort((a,b) => b.y - a.y).sort((a,b) => { if (a.y === b.y) return a.val - b.val; return 0; }) return xCoordMap[key].map(obj => obj.val); }); return vertArrays; };
Обсуждение и выводы
Я действительно сосредоточился на выкладывать данные узла в структуру данных и сортировать ее по значению x, когда он добавляется. Я чувствовал, что это быстрее, чем любой метод, который сначала ищет, а затем сортирует позже. Особенно потому, что я использую хеш-таблицу для хранения узлов с тем же значением x.
Однако я мог бы сделать еще несколько думать о сортировке массивов моего узла контейнера по значению Y и значение узла при добавлении, а не перед возвратом. Я верю, что смогу сделать это в O (n), если бы я попытался поставить новые узлы в правильном месте при добавлении их вместо o (nlog (n)) сортировки, что я сделал, чтобы вернуть решение.
Оригинал: “https://dev.to/drewhsu86/leetcode-daily-vertical-order-traversal-of-binary-tree-3d8j”