иногда нет умной и информативной каламбура в заголовке поста
В жизни каждого программиста наступает момент, когда он должен пройти Cracking the Coding Interview. Это время для меня настало, и теперь я полностью поглощен структурами данных и алгоритмами.
Сегодня я покажу вам кое-что, что я сделал с помощью односвязных списков.
Сначала я приготовил. Оказывается, вам не всегда нужен класс LinkedList, в котором хранится весь список - если вы можете сослаться на нижний узел, он будет знать об узле над ним (который, в свою очередь, будет знать об узле над ним). (В конце концов, мы будем использовать атрибут self.list из инициализатора для хранения дополнительной информации, но нам это не нужно.)
class LinkedListNode attr_accessor :value, :next_node, :list def initialize(value, next_node=nil) @value = value @list = [] @next_node = next_node end def print p @value if @next_node @next_node.print end end end
Затем, поскольку я слышал, что это частый вопрос на собеседовании, я решил придумать способ их изменить. Я действительно копаю рекурсию, когда она себя ведет.
def reverse(bottom_node, previous=nil) head = bottom_node.next_node bottom_node.next_node = previous if head reverse(head, bottom_node) else bottom_node end end
Затем я решил, что хочу посмотреть, могу ли я использовать рекурсию для создания связного списка из массива. Отвечать? Да, я могу!
def generate(array, node=nil) if array.empty? node elsif node.nil? new_node = LinkedListNode.new(array.pop) generate(array, new_node) else new_node = LinkedListNode.new(array.pop, node) generate(array, new_node) end end
В конце концов, я решил заняться одной из проблем, описанных в книге. Проблема заключалась в следующем:
У вас есть два числа, представленных связанным списком, где каждый узел содержит одну цифру. Цифры сохраняются в обратном порядке, так что цифра 1 находится в начале списка. Напишите функцию, которая складывает два числа и возвращает сумму в виде связанного списка.
(7->1->6) + (5->9->2) => (9->1->2) 617 + 295 = 912
Во-первых, я составил два списка, которые нам нужны, чтобы решить проблему.
node1 = LinkedListNode.new(6) node2 = LinkedListNode.new(1, node1) list1 = LinkedListNode.new(7, node2) node3 = LinkedListNode.new(2) node4 = LinkedListNode.new(9, node3) list2 = LinkedListNode.new(5, node4)
Наконец, пришло время использовать мой атрибут self.list для хранения всего списка в виде массива.
class LinkedListNode … def numberify(node, array=@list) array.push(self.value) if @next_node @next_node.numberify(self, array) end end end list1.numberify(list1) p list1.list => [7, 1, 6] list2.numberify(list2) p list2.list => [5, 9, 2]
Когда у меня появился этот метод, я мог перевернуть эти массивы, а затем преобразовать их в числа.
class LinkedListNode … def reverse_n_join self.list.reverse.join(‘’).to_i end end
Итак, чтобы суммировать оба списка:
def sum(lista, listb) lista.numberify(lista) listb.numberify(listb) return lista.reverse_n_join + listb.reverse_n_join end p sum(list1, list2) => 912
Но, наконец, мне нужно снова превратить это целое число в связанный список! К счастью, я сделал этот метод «генерации» раньше. Я сделал это для массивов, поэтому мне нужно несколько раз принудить данные, чтобы они работали здесь.
generate(sum(list1,list2).to_s.split(‘’).map(&:to_i)).print =>9 =>1 =>2
Фух! Я уверен, что я мог бы провести некоторый рефакторинг, но пока я оставлю вам суть всего этого кода.