18
\$\begingroup\$

The height of a binary tree is the distance from the root node to the node child that is farthest from the root.

Below is an example:

           2 <-- root: Height 1
          / \
         7   5 <-- Height 2
        / \   \
       2   6   9 <-- Height 3
          / \  /
         5  11 4 <-- Height 4 

Height of binary tree: 4

Definition of a Binary Tree

A tree is an object that contains a signed integer value and either two other trees or pointers to them.

The structure of the binary tree struct looks something like the following:

typedef struct tree
{
  struct tree * l;

  struct tree * r;

  int v;

} tree;

The challenge:

Input

The root of a binary tree

Output

The number that represents the height of a binary tree

Assuming you are given the root of a binary tree as input, write the shortest program that calculates the height of a binary tree and returns the height. The program with least amount of bytes (accounting whitespaces) wins.

\$\endgroup\$
  • 4
    \$\begingroup\$ What do languages without pointers take? \$\endgroup\$ – Jonathan Allan Aug 4 at 17:37
  • 4
    \$\begingroup\$ ...but then my tree object could just have a property, say h. Might be better to define a specific structure made just of lists for the purpose of this challenge. \$\endgroup\$ – Jonathan Allan Aug 4 at 17:40
  • 11
    \$\begingroup\$ @T.Salim In the future, please consider posting in the sandbox first. \$\endgroup\$ – wizzwizz4 Aug 4 at 17:44
  • 1
    \$\begingroup\$ So, is a valid representation a list of length 3 [root_value, left_node, right_node] where each of left_node and right_node are also binary trees acceptable? It'll be trivial in many languages, but might be fun in some others. \$\endgroup\$ – Jonathan Allan Aug 4 at 17:50
  • 3
    \$\begingroup\$ Can you edit the question to include what constitutes a valid binary structure? Perhaps a definition like a tree is an object that contains a value and either two other trees or pointers to them. A definition that is inclusive of languages without objects would also be nice too. \$\endgroup\$ – Jo King Aug 4 at 21:54

19 Answers 19

11
\$\begingroup\$

Jelly, 3 bytes

ŒḊ’

A monadic Link accepting a list representing the tree: [root_value, left_tree, right_tree], where each of left_tree and right_tree are similar structures (empty if need be), which yields the height.

Try it online!

How?

Pretty trivial in Jelly:

ŒḊ’ - Link: list, as described above
ŒḊ  - depth
  ’ - decremented (since leaves are `[value, [], []]`)
\$\endgroup\$
  • \$\begingroup\$ Jonathon Allen, that is an interesting language you are using. As a newcomer, may you provide a link or a website referral that tutors people how to use Jelly? \$\endgroup\$ – T. Salim Aug 4 at 17:53
  • 4
    \$\begingroup\$ Click the link in the header - it's a golfing Language developed by Dennis, one of the site's moderators. \$\endgroup\$ – Jonathan Allan Aug 4 at 17:56
  • 2
    \$\begingroup\$ I wonder how controversial it would be to represent a leaf as x instead of [x, [], []]... \$\endgroup\$ – Erik the Outgolfer Aug 4 at 18:19
  • \$\begingroup\$ @EriktheOutgolfer To keep with the "pointer" and "struct" nature of the question I think every node should be of the same form. \$\endgroup\$ – Jonathan Allan Aug 4 at 18:28
10
\$\begingroup\$

Python 2,  35  33 bytes

Thanks to Arnauld for noicing an oversight and saving 4.

f=lambda a:a>[]and-~max(map(f,a))

A recursive function accepting a list representing the tree: [root_value, left_tree, right_tree], where each of left_tree and right_tree are similar structures (empty if need be), which returns the height.

Try it online!

Note that [] will return False, but in Python False==0.

\$\endgroup\$
  • \$\begingroup\$ The same person is allowed to give two different answers to the same question? \$\endgroup\$ – T. Salim Aug 4 at 18:36
  • 6
    \$\begingroup\$ Yeah, of course, golf is a competition at a language level. Even a second entry in the same language is sometimes acceptable, if the approach is very different. \$\endgroup\$ – Jonathan Allan Aug 4 at 18:39
  • \$\begingroup\$ @Arnauld Guess so (I'd assumed non-integers might be present for some reason) \$\endgroup\$ – Jonathan Allan Aug 4 at 18:46
6
\$\begingroup\$

Haskell, 33 bytes

h L=0 
h(N l r _)=1+max(h l)(h r)

Using the custom tree type data T = L | N T T Int, which is the Haskell equivalent of the C struct given in the challenge.

Try it online!

\$\endgroup\$
6
\$\begingroup\$

Perl 6, 25 bytes

{($_,{.[*;*]}...*eqv*)-2}

Input is a 3-element list (l, r, v). The empty tree is the empty list.

Try it online!

Explanation

{                       }  # Anonymous block
    ,        ...  # Sequence constructor
  $_  # Start with input
     {.[*;*]}  # Compute next element by flattening one level
               # Sadly *[*;*] doesn't work for some reason
                *eqv*  # Until elements doesn't change
 (                   )-2  # Size of sequence minus 2

Old solution, 30 bytes

{+$_&&1+max map &?BLOCK,.[^2]}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ The &?BLOCK trick is interesting but it's a couple of bytes shorter to assign the block to $! \$\endgroup\$ – Jo King Aug 4 at 21:49
  • \$\begingroup\$ @JoKing I don't know. Storing the challenge solution in a volatile global like $! or $/ feels like cheating to me. \$\endgroup\$ – nwellnhof Aug 4 at 21:56
  • \$\begingroup\$ (Ab)using variables like $! and $/ is fairly standard practice for golfing P6. \$\endgroup\$ – guifa Aug 6 at 4:47
6
\$\begingroup\$

05AB1E, 11 7 5 bytes

Δ€`}N

-4 bytes thanks to @ExpiredData.
-2 bytes thanks to @Grimy.

Input format is similar as the Jelly answer: a list representing the tree: [root_value, left_tree, right_tree], where each of left_tree and right_tree are similar structures (optionally empty). I.e. [2,[7,[2,[],[]],[6,[5,[],[]],[11,[],[]]]],[5,[],[9,[4,[],[]],[]]]] represents the tree from the challenge description.

Try it online or verify a few more test cases.

Explanation:

Δ     # Loop until the (implicit) input-list no longer changes:
  €`  #  Flatten the list one level
}N    # After the loop: push the 0-based index of the loop we just finished
      # (which is output implicitly as result)

Note that although 05AB1E is 0-based, the changes-loop Δ causes the output index to be correct, because it needs an additional iteration to check it no longer changes.

\$\endgroup\$
  • 1
    \$\begingroup\$ 7 bytes? \$\endgroup\$ – Expired Data Aug 5 at 10:01
  • \$\begingroup\$ @ExpiredData Ah, of course.. Thanks! :) \$\endgroup\$ – Kevin Cruijssen Aug 5 at 10:04
  • 1
    \$\begingroup\$ 5 bytes \$\endgroup\$ – Grimy Aug 19 at 13:05
  • \$\begingroup\$ @Grimy I thought using the index outside a loop only worked in the legacy code.. :S Thanks! \$\endgroup\$ – Kevin Cruijssen Aug 19 at 13:10
5
\$\begingroup\$

JavaScript (ES6),  35  33 bytes

Input structure: [[left_node], [right_node], value]

f=([a,b])=>a?1+f(f(a)>f(b)?a:b):0

Try it online!

Commented

f =                       // f is a recursive function taking
([a, b]) =>               // a node of the tree split into
                          // a[] = left child, b[] = right child (the value is ignored)
  a ?                     // if a[] is defined:
    1 +                   //   increment the final result for this branch
    f(                    //   and add:
      f(a) > f(b) ? a : b //     f(a) if f(a) > f(b) or f(b) otherwise
    )                     //
  :                       // else:
    0                     //   stop recursion and return 0
\$\endgroup\$
  • \$\begingroup\$ Looks like you can save a byte with a&&-~. \$\endgroup\$ – Shaggy Aug 4 at 23:03
  • 1
    \$\begingroup\$ @Shaggy That would lead to comparisons with undefined. \$\endgroup\$ – Arnauld Aug 4 at 23:12
4
\$\begingroup\$

C, 43 bytes

h(T*r){r=r?1+(int)fmax(h(r->l),h(r->r)):0;}

Structure of binary tree is the following:

typedef struct tree
{
  struct tree * l;

  struct tree * r;

  int v;

} tree;
\$\endgroup\$
  • 2
    \$\begingroup\$ 55 bytes Try it online! Some C-specific golfing tricks are here! \$\endgroup\$ – ErikF Aug 4 at 20:41
  • 1
    \$\begingroup\$ @ErikF Or 45 bytes \$\endgroup\$ – Arnauld Aug 4 at 20:46
  • \$\begingroup\$ Thanks ErikF and Arnauld. I should try out the ternary operator more often instead of if-else-if chains. \$\endgroup\$ – T. Salim Aug 4 at 20:49
  • 2
    \$\begingroup\$ 43 bytes \$\endgroup\$ – nwellnhof Aug 4 at 21:36
  • 3
    \$\begingroup\$ If your submission relies on flags, can you please add them to the header of your submission? \$\endgroup\$ – Jo King Aug 4 at 22:20
4
\$\begingroup\$

JavaScript (Node.js), 32 bytes

f=a=>/,,/.test(a)&&f(a.flat())+1

Try it online!

Using the name flat instead of flatten or smoosh is a great idea for code golf.

Using [] for null node in the tree, and [left, right, value] for nodes. value here is an integer.

\$\endgroup\$
4
\$\begingroup\$

Wolfram Language (Mathematica), 10 bytes

Depth@#-2&

Try it online! Takes input as a nested list {v, l, r}.

\$\endgroup\$
  • \$\begingroup\$ If 2[7[2,6[5,11]],5[9[4,],]] is a valid representation of the tree, Depth works \$\endgroup\$ – attinat Aug 15 at 23:50
3
\$\begingroup\$

Haskell, 28 bytes

Using the following data definition:

data T a = (:&) a [T a]

The height is:

h(_:&x)=foldr(max.succ.h)0 x
\$\endgroup\$
2
\$\begingroup\$

Scheme, 72 Bytes

(define(f h)(if(null? h)0(+ 1(max(f(car(cdr h)))(f(car(cdr(cdr h))))))))

More Readable Version:

(define (f h)
   (if (null? h)
      0
      (+ 1 
         (max
             (f (car (cdr h)))
             (f (car (cdr (cdr h))))
         )
      )
   )
)

Using lists of the form (data, left, right) to represent a tree. E.g.

   1
  / \
  2  3
 /\
 4 5

is represented as: (1 (2 (4 () ()) (5 () ())) (3 () ())

(1
   (2
      (4 () ())
```   (5 () ())
   (3 () ())
)

Try it Online!

\$\endgroup\$
2
\$\begingroup\$

R, 51 bytes

function(L){while(is.list(L<-unlist(L,F)))T=T+1;+T}

Try it online!

  • Input: a nested list in the format : list(ROOT_ELEMENT, LEFT_TREE, RIGHT_TREE)

  • Algorithm: Iteratively flattens the tree by one level until it becomes a flat vector : the iterations count corresponds to the max depth.

Inspired by @KevinCruijssen solution


Recursive alternative :

R, 64 bytes

`~`=function(L,d=0)'if'(is.list(L),max(L[[2]]~d+1,L[[3]]~d+1),d)

Try it online!

Redefines the function/operator '~' making it able to compute the max depth of a tree stored in a list structure.

The list structure of a tree is in the format : list(ROOT_ELEMENT, LEFT_TREE, RIGHT_TREE)

  • -2 thanks to @Giuseppe
\$\endgroup\$
  • \$\begingroup\$ why do you use d=1 and then d-1 at the end? Couldn't you start at 0? \$\endgroup\$ – Giuseppe Aug 5 at 16:34
  • \$\begingroup\$ Also I switched > to ~ here so the test cases are easier to input \$\endgroup\$ – Giuseppe Aug 5 at 16:34
  • \$\begingroup\$ @Giuseppe: of course...I was missing the obvious 🤦‍♂️ \$\endgroup\$ – digEmAll Aug 5 at 20:48
1
\$\begingroup\$

Japt, 8 bytes

@eU=c1}a

Try it

Original, 9 bytes

Ω¡ÒßXÃrw

Try it

\$\endgroup\$
1
\$\begingroup\$

K (ngn/k), 4 bytes

Solution:

#,/\

Try it online!

Explanation:

I think I may have missed the point.

Representing a tree as the 3-item list (parent-node;left-child;right-child), the example can be represented as

(2;
  (7;
    (,2);
    (6;
      (,5);
      (,11)
    )
  );
  (5;
    ();
    (9;
      (,4);
      ()
    )
  )
)

or: (2;(7;(,2);(6;(,5);(,11)));(5;();(9;(,4);()))).

So the solution is to iteratively flatten, and count the iterations:

#,/\ / the solution
   \ / iterate
 ,/  / flatten
#    / count
\$\endgroup\$
0
\$\begingroup\$

Charcoal, 29 bytes

⊞θ⁰⊞υθFυ«≔⊕⊟ιθFΦι∧κλ⊞υ⊞Oκθ»Iθ

Try it online! Link is to verbose version of code. Temporarily modifies the tree during processing. Explanation:

⊞θ⁰

Push zero to the root node.

⊞υθ

Push the root node to the list of all nodes.

Fυ«

Perform a breadth-first search of the tree.

≔⊕⊟ιθ

Get the depth of this node.

FΦι∧κλ

Loop over any child nodes.

⊞υ⊞Oκθ

Tell the child node its parent's depth and push it to the list of all nodes.

»Iθ

Once all the nodes have been traversed print the depth of the last node. Since the traversal was breadth-first, this will be the height of the tree.

\$\endgroup\$
0
\$\begingroup\$

Stax, 5 bytes

▐▌µ╡⌂

Run and debug it

Stax has neither pointers nor null values, so I represent the input like [2,[7,[2,[],[]],[6,[5,[],[]],[11,[],[]]]],[5,[],[9,[4,[],[]],[]]]]. Maybe that's an unfair advantage, but it was the closest I could get.

Unpacked, ungolfed, and commented, the code looks like this.

        The input starts on top of the input stack
Z       Tuck a zero underneath the top value in the stack.  Both values end up on the main stack.
D       Drop the first element from array
F       For each remaining element (the leaves) run the rest of the program
  G^    Recursively call the entire program, then increment
  T     Get maximum of the two numbers now ow the stack

Run this one

\$\endgroup\$
0
\$\begingroup\$

Kotlin, 45 bytes

val Tree.h:Int get()=1+maxOf(l?.h?:0,r?.h?:0)

Assuming the following class is defined

class Tree(var v: Int, var l: Tree? = null, var r: Tree? = null)

Try it online

\$\endgroup\$
0
\$\begingroup\$

Julia, 27 bytes

f(t)=t≢()&&maximum(f,t.c)+1

With the following struct representing the binary tree:

struct Tree
    c::NTuple{2,Union{Tree,Tuple{}}}
    v::Int
end

c is a tuple representing the left and right nodes and the empty tuple () is used to signal the absence of a node.

\$\endgroup\$
0
\$\begingroup\$

Kotlin, 42 bytes

fun N.c():Int=maxOf(l?.c()?:0,r?.c()?:0)+1

Try it online!

Where

data class N(val l: N? = null, val r: N? = null, val v: Int = 0)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.