Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save alvinlau/54acca265d07f0284d464ed285186760 to your computer and use it in GitHub Desktop.

Select an option

Save alvinlau/54acca265d07f0284d464ed285186760 to your computer and use it in GitHub Desktop.
105. Construct Binary Tree from Preorder and Inorder Traversal
# https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
# Given two integer arrays preorder and inorder where preorder is the preorder traversal of a binary tree and inorder is the inorder traversal of the same tree, construct and return the binary tree.
# Example 1:
# Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
# Output: [3,9,20,null,null,15,7]
# Example 2:
# Input: preorder = [-1], inorder = [-1]
# Output: [-1]
# Constraints:
# 1 <= preorder.length <= 3000
# inorder.length == preorder.length
# -3000 <= preorder[i], inorder[i] <= 3000
# preorder and inorder consist of unique values.
# Each value of inorder also appears in preorder.
# preorder is guaranteed to be the preorder traversal of the tree.
# inorder is guaranteed to be the inorder traversal of the tree.
# Definition for a binary tree node.
# class TreeNode
# attr_accessor :val, :left, :right
# def initialize(val = 0, left = nil, right = nil)
# @val = val
# @left = left
# @right = right
# end
# end
# @param {Integer[]} preorder
# @param {Integer[]} inorder
# @return {TreeNode}
def build_tree(preorder, inorder)
subtree(preorder, inorder)[:node]
end
# general strategy
# https://www.geeksforgeeks.org/construct-tree-from-given-inorder-and-preorder-traversal/
# https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/
# given the preoder list, look for the first preorder item in the inorder list
# use it as a node to split, build subtrees from the left and right lists
# and use those as the left & right children of the node
# return the node along with rest of preorder list for items that still need to be found
def subtree(preorder, inorder)
return {node: nil, rest: preorder} unless preorder
# value check?
return {node: TreeNode.new(preorder.first), rest: preorder[1..-1]} if inorder.size == 1
# another base case
if inorder.size == 2
preorder2 = preorder.take(2)
if preorder2 == inorder
return {
node: TreeNode.new(inorder.first, nil, TreeNode.new(inorder.last)),
rest: preorder.drop(2)
}
else
return {
node: TreeNode.new(inorder.last, TreeNode.new(inorder.first), nil),
rest: preorder.drop(2)
}
end
end
val, *rest = preorder
node = TreeNode.new(val)
result = {node:, rest:}
# O(n^2) to O(n) improvement (for this part at least)
# can use an item => index lookup hash of the inorder list
# but need to update with offset of the reduced inorder list
i = inorder.index(val)
# look on the list on the left & right side of the split at node
# except when the node is at the left/right end
if preorder.first == inorder.first
left, right = [], inorder.drop(1)
elsif preorder.first == inorder.last
left, right = inorder[0..-2], []
else
left, right = inorder[0..i-1], inorder[i+1..-1]
end
# if there's no left or right subtrees, the left/right fields will be nil by default
unless left.empty?
result = subtree(rest, left)
node.left = result[:node]
end
unless right.empty?
result = subtree(result[:rest], right)
node.right = result[:node]
end
{node:, rest: result[:rest]}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment