Constructing Binary Tree from Inorder and Postorder Traversal - algorithm

I am trying to construct a binary tree from postorder and inorder traversal. I believe the recursion part is correct however I'm not sure about the base cases. Any pointers would be appreciated.
I have tried different combination of base cases but I can't seem to get it working.
class BinaryTreeNode:
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
def binary_tree_from_postorder_inorder(postorder, inorder):
node_to_inorder_idx = {data: i for i, data in enumerate(inorder)}
def helper(
postorder_start, postorder_end, inorder_start, inorder_end
):
if postorder_end >= postorder_start or inorder_end <= inorder_start:
return None
root_inorder_idx = node_to_inorder_idx[postorder[postorder_start]]
left_subtree_size = root_inorder_idx - inorder_start
root = BinaryTreeNode(postorder[postorder_start])
root.right = helper(
postorder_start - 1,
postorder_start - 1 - left_subtree_size,
root_inorder_idx + 1,
inorder_end,
)
root.left = helper(
postorder_start - 1 - left_subtree_size,
postorder_end,
inorder_start,
root_inorder_idx,
)
return root
return helper(len(postorder) - 1, -1, 0, len(inorder))
def inorder(tree):
stack = []
results = []
while stack or tree:
if tree:
stack.append(tree)
tree = tree.left
else:
tree = stack.pop()
results.append(tree.data)
tree = tree.right
return results
inorder = ["F", "B", "A", "E", "H", "C", "D", "I", "G"]
postorder = ["F", "A", "E", "B", "I", "G", "D", "C", "H"]
root_pos_in = binary_tree_from_postorder_inorder(postorder, inorder)
print(inorder(root_pos_in))
Inputs:
inorder = ["F", "B", "A", "E", "H", "C", "D", "I", "G"]
postorder = ["F", "A", "E", "B", "I", "G", "D", "C", "H"]
Actual output using inorder traversal:
["A", "B", "E", "H", "C"]
Expected output:
["F", "B", "A", "E", "H", "C", "D", "I", "G"]

It's been a while since I dealt with Python, but that looks like a lot of code for what seems a simple algorithm.
Here is a an example of the application of the algorithm:
We start with
postorder | inorder
-----------|----------
|
FAEBIGDCH | FBAEHCDIG
^ |
| |
`-+-------------- last value of postorder: 'H': this is the root value
|
FAEBIGDCH | FBAEHCDIG
| ^
| |
| `------- index of 'H' in inorder: 4
|
FAEB_.... | FBAE_....
^ | ^
| | |
| | `--------- everything before index 4
| |
`-------+-------------- everything before index 4
|
....IGDC_ | ...._CDIG
^ | ^
| | |
| | `---- everything beginning with index 5 (4 + 1)
| |
`---+-------------- everything between index 4 and the 'H' at the end
|
FAEB | FBAE
^ | ^
| | |
`-------+---+---------- recur on these if not empty: this is the left child
|
IGDC | CDIG
^ | ^
| | |
`--+--------+----- recur on these if not empty: this is the right child
This will quickly lead us to a tree like
H
|
+--------+--------+
| |
B C
| |
+-----+-----+ +-----+
| | |
F E D
| |
+---+ +---+
| |
A G
+-+
|
I
So while I can't really critique your Python, I can offer a pretty simple JS version:
const makeTree = (
postord, inord,
len = postord.length, val = postord[len - 1], idx = inord.indexOf(val)
) =>
len == 1
? {val}
: {
val,
...(idx > 0 ? {left: makeTree(postord.slice(0, idx), inord.slice(0, idx))} : {}),
...(idx < len - 1 ? {right: makeTree(postord.slice(idx, len - 1), inord.slice(idx + 1, len))} : {})
}
const postOrder = ["F", "A", "E", "B", "I", "G", "D", "C", "H"]
const inOrder = ["F", "B", "A", "E", "H", "C", "D", "I", "G"]
console .log (
makeTree (postOrder, inOrder)
)

After fiddling for a little longer, I was able to fix the problem. See my updated function below:
def binary_tree_from_postorder_inorder(postorder, inorder):
if not inorder or not postorder or len(postorder) != len(inorder):
return None
node_to_inorder_idx = {data: i for i, data in enumerate(inorder)}
def helper(postorder_start, postorder_end, inorder_start, inorder_end):
if postorder_start > postorder_end or inorder_start > inorder_end:
return None
root_index = node_to_inorder_idx[postorder[postorder_end]]
left_subtree_size = root_index - inorder_start
return BinaryTreeNode(
postorder[postorder_end],
helper(
postorder_start,
postorder_start + left_subtree_size - 1,
inorder_start,
root_index - 1,
),
helper(
postorder_start + left_subtree_size,
postorder_end - 1,
root_index + 1,
inorder_end,
),
)
return helper(0, len(postorder) - 1, 0, len(inorder) - 1)

Related

Return string value to array from loop (Ruby)

Not sure if that's the term I should use for it but what I'm trying to do is add len amount of characters to an array, then output that to a .txt. I have the generation done to my satisfaction but I'm not sure how to pack the strings into an array. Right now it just spits out all the strings into the console because of the puts statement, just to make sure it works.
#Password list generator by Nightc||ed, ©2015
norm = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
caps = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
puts "How many passwords would you like to generate?"
num = gets.to_i
system "cls"
puts "Password length (1-x):"
len = gets.to_i
system "cls"
puts """
Which characters would you like to use?
[1] a-z, 0-9
[2] A-Z, 0-9
[3] a-z, A-Z, 0-9
"""
arr = []
type = gets.chomp
if type == "1"
arr = [norm,nums]
elsif type == "2"
arr = [caps,nums]
elsif type == "3"
arr = [norm,caps,nums]
else
exit
end
num.times do |pass|
len.times do |char|
arr2 = arr.to_a.sample
char = arr2.to_a.sample
puts char
end
end
sleep
here your code simplified
#Password list generator by Nightc||ed, ©2015
norm = [*"a".."z"]
caps = [*"A".."Z"]
nums = [*0..9]
num, len, type = [
"How many passwords would you like to generate?",
"Password length (1-x):",
"Which characters would you like to use?
[1] a-z, 0-9
[2] A-Z, 0-9
[3] a-z, A-Z, 0-9"].map do |msg|
puts msg
gets.to_i
end
arr = case type
when 1 then
norm + nums
when 2 then
caps + nums
when 3 then
norm + caps + nums
else
exit
end
passwords = num.times.map { arr.sample(len).join }
puts passwords.inspect
sleep
I think you can simplify your life by replacing the if... and below with the following:
case type
when "1"
arr = [norm,nums].flatten
when "2"
arr = [caps,nums].flatten
when "3"
arr = [norm,caps,nums].flatten
else
exit
end
passwd_set = []
num.times { passwd_set << arr.sample(len).join }
p passwd_set
I find case statements easier to read, and more easily extended. Flattening the arrays makes it so sample can directly produce the desired number of characters/symbols, and those can be joined to produce a string which can be appended to your passwd_set array.
You can add to an array using the << method. For example:
arr = []
3.times do |el|
arr << el
end
arr.inspect #=> [0, 1, 2]
Another option would be the push method:
arr = []
(0..2).each { |el| arr.push(el)}

Algorithm to sort three kinds of balls

We have N balls of three different types: red(r), blue(b), and white(w).
I need to sort them so that red balls appear firsts, then all white balls and finally all blue balls.
Example:
In: bwrwrbbrwwrb
string[] arrBalls = { "b", "w", "r", "w", "r", "b", "b", "r", "w", "w", "r", "b" };
Out:rrrrwwwwbbbb
I need to found a linear O(n) algorithm.
Update: C# code
string[] arrBalls = { "b", "w", "r", "w", "r", "b", "b", "r", "w", "w", "r", "b" };
int index_red = 0;
int index_blue = arrBalls.Length - 1;
for (int i = 0; i < arrBalls.Length; i++)
{
if (arrBalls[i] == "r" && index_red != i)
{
string TempRed = arrBalls[index_red];
arrBalls[index_red] = arrBalls[i];
arrBalls[i] = TempRed;
if (arrBalls[index_red] == "r")
{
while(arrBalls[index_red] == "r")index_red++;
}
else
{
index_red++;
}
}
if (arrBalls[i] == "b" && index_blue != i)
{
string TempRed = arrBalls[index_blue];
arrBalls[index_blue] = arrBalls[i];
arrBalls[i] = TempRed;
if (arrBalls[index_blue] == "b")
{
while (arrBalls[index_blue] == "b") index_blue--;
}
else
{
index_blue--;
}
}
}
You count each one of the three types of balls into 3 variables. Let's say you counted R red balls, B blue ones and W white ones. Then you output R "r", followed by W "w", followed by B "b".

Caesar Cipher shift on a string using shifting number

I have this question.
Using the Ruby language, have the function CaesarCipher(str,num) take the str parameter and perform a Caesar Cipher shift on it using the num parameter as the shifting number. A Caesar Cipher works by shifting each letter in the string N places down in the alphabet (in this case N will be num). Punctuation, spaces, and capitalization should remain intact. For example if the string is "Caesar Cipher" and num is 2 the output should be "Ecguct Ekrjgt".
Any my code looks like this. I think the onlt problem i have is to update each letter and then each word within the loops. please help. thank you
def Caesar_cipher(str, num)
if num > 25
num -= 26
end
alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
str = str.split(" ")
str.each do |word|
word.each_char do |c|
if alphabet.include?(c)
n = alphabet.index(c) + num
if n > 25
n -= 26
end
c = alphabet[n]
end
end
end
return str
end
puts Caesar_cipher("zabcd", 1) // "zabcd"
str = str.split("")
alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
alphabet2 = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
while num > 25
num -= 26
end
str = str.map do |char|
if alphabet.include?(char)
n = alphabet.index(char) + num
while n > 25
n -= 26
end
char = alphabet[n]
elsif alphabet2.include?(char)
m = alphabet2.index(char) + num
while m > 25
m -= 26
end
char = alphabet2[m]
else
char
end
char
end
return str.join
end
def cipher_shift(s, n)
letters = [*'a'..'z']
s.chars.map {|x| letters.include?(x.downcase) ? (x.ord + n).chr : x}.join
end

Array to set conversion returning a set with hexadecimal value

I am taking input from a file and converting each line into an array, then converting that array into a set. But on conversion the set returns something like this:
<Set:0x6268f8>
But running the same thing on IRB returns correct values.
require 'set'
n,p = gets.chomp.split.map { |e| e.to_i }
arr = gets.chomp.split( ).map{|x| x.to_i}
print arr
puts
old_set = arr.to_set
print old_set
if old_set.length != 1
print "NO"
exit
end
input file:
3 6
0 0 0 0 0 0
1 1 1 1 1 1
2 2 2 2 2 2
On running this I get:
C:\Ruby\kumar>ruby so.rb < abc.txt
[0, 0, 0, 0, 0, 0]
#<Set:0x3aad30>
On IRB:
irb(main):010:0> arr = gets.chomp.split("")
aabbddefyy
=> ["a", "a", "b", "b", "d", "d", "e", "f", "y", "y"]
irb(main):011:0> se=arr.to_set
=> #<Set: {"a", "b", "d", "e", "f", "y"}>
irb(main):012:0> se
=> #<Set: {"a", "b", "d", "e", "f", "y"}>
That output #<Set:0x3aad30> means that the result is a Set object, and the hex values is the memory address of that instance object. If you want to see the values you could do it with old_set.inspect. You can read more about the Set class here

How to convert array with ranges in to alone array in ruby

I have some array
>> a = ["a..c", "0..2"]
=> ["a..c", "0..2"]
I need convert this array to another array
>> b = ("a".."c").to_a + (0..2).to_a
=> ["a", "b", "c", 0, 1, 2]
How I can do it?
a.flat_map do |string_range|
from, to = string_range.split("..", 2)
(from =~ /^\d+$/ ? (from.to_i..to.to_i) : (from..to)).to_a
end
#=> => ["a", "b", "c", 0, 1, 2]
what about this?
a = ["a..c", "0..2"]
b = a.map { |e| Range.new( *(e).split('..') ).to_a }.flatten
no flat_map used so it works the same on all versions
as #steenslag correctly mentioned, this version does not convert to integers.
here is a version that does:
b = a.map do |e|
Range.new( *(e).split('..').map{ |c| c =~ /\A\d+\Z/ ? c.to_i : c } ).to_a
end.flatten
see it in action here
a = ["a..c", "0..2"]
b = a.flat_map{|str| Range.new(*str.split('..')).to_a} # => ["a", "b", "c", "0", "1", "2"]
p b.map!{|v| Integer(v) rescue v} # => ["a", "b", "c", 0, 1, 2]

Resources