>

Problem 2

Given a list of trees (as pointers to their roots), return the biggest score of all nodes in all trees.

Definition of a Node:

type Node struct {
	id       uuid.UUID
	score    int
	children []*Node
}
func findBiggestScoreHelper(node *Node, biggestScore int) int {
	return 0
}

NOTE: Since trees are by definition acyclic (i.e., there is exactly one path to reach each node from the root), we do not need to maintain a list of visited nodes. This was an error on the interviewer's part, as the original function signature included visited map[*Node]bool in order to keep track of visited nodes.


Solution

Using either breadth-first search or depth-first search, traverse each tree keeping track of the biggest score across all nodes.

package main

import (
	"fmt"
	"math/rand"

	"github.com/google/uuid"
)

// Node is a node in the tree.
type Node struct {
	// id is a random UUID.
	id uuid.UUID
	// score is a random non-negative integer from 0 to 99 inclusive.
	score int
	// children is a list of pointers to the node's children.
	children []*Node
}

// String prints the node's score.
func (n *Node) String() string {
	return fmt.Sprintf("Node(score: %d)", n.score)
}

// NewNode creates a new node and returns a pointer to it.
func NewNode() *Node {
	node := new(Node)
	node.id = uuid.New()
	node.score = rand.Intn(100)
	node.children = []*Node{}
	return node
}

// createTreeHelper creates a tree of the specified depth by recursively adding
// three children to each node until the desired depth is reached.
//
// The depth (or height) of a tree is the length of the longest path from the
// root node to any leaf node in the tree. A tree with a depth of 0 is a single
// node, the root.
func createTreeHelper(parent *Node, depth int) *Node {
	if depth <= 1 {
		return parent
	}
	// Each descendant of parent has three children.
	for i := 0; i < 3; i++ {
		parent.children = append(parent.children, createTree(depth-1))
	}
	return parent
}

// createTree creates a new tree of depth `depth`.
//
// Example:
//
//	   ●
//	 / | \
//	●  ●  ●  Depth = 1
func createTree(depth int) *Node {
	root := NewNode()
	return createTreeHelper(root, depth)
}

// findBiggestScore finds the biggest score of all the nodes in a list of
// trees.
//
// NOTE: Since trees are by definition acyclic, we do not need to maintain a
// list of visited nodes.
func findBiggestScore(trees []*Node) int {
	biggestScore := 0
	for _, root := range trees {
		score := findBiggestScoreHelper(root, 0)
		if score > biggestScore {
			biggestScore = score
		}
	}
	return biggestScore
}

// findBiggestScoreHelper uses depth-first search to find the biggest score of
// all the nodes in a tree.
//
// When using depth-first search, the biggest score is carried throughout the
// tree traversal. Effectively, the biggest score is found for each subtree.
func findBiggestScoreHelper(node *Node, biggestScore int) int {
	if node == nil {
		return biggestScore
	}

	if node.score > biggestScore {
		biggestScore = node.score
	}

	for _, child := range node.children {
		score := findBiggestScoreHelper(child, biggestScore)
		if score > biggestScore {
			biggestScore = score
		}
	}

	return biggestScore
}
Source

grind.rip

From Grind Hell, with Love



Solution for Problem 2 of the Architect.io technical interview