1600. Throne Inheritance
Problem Description
You need to implement a throne inheritance system for a kingdom. The kingdom has a hierarchical family structure starting with the king, followed by his children, grandchildren, and so on. The inheritance order follows a specific rule where the throne passes from a person to their oldest child who hasn't been considered yet, and if all children have been considered (or there are no children), it goes back up to find the next eligible relative.
The inheritance order follows these rules:
- Start with the king
- For any person, their oldest child who hasn't been added to the order comes next
- If a person has no children or all their children are already in the order, go back to their parent and find the parent's next oldest child
- This process continues until all living family members are included
You need to implement a ThroneInheritance
class with the following methods:
- Constructor
ThroneInheritance(kingName)
: Initialize the system with the king's name birth(parentName, childName)
: Record thatparentName
had a child namedchildName
death(name)
: Mark a person as dead (they should be excluded from the inheritance order but their descendants can still inherit)getInheritanceOrder()
: Return the current inheritance order as a list, excluding dead people
For example, if we have King → Alice (older) and Bob (younger) → Jack (Alice's son):
- The inheritance order would be:
["king", "Alice", "Jack", "Bob"]
- This follows the pattern: king → king's oldest child (Alice) → Alice's child (Jack) → back to king's next child (Bob)
The solution uses a graph representation where each person's children are stored in a hash table. When generating the inheritance order, it performs a depth-first traversal starting from the king, adding each living person to the result and recursively visiting all their children in order.
Flowchart Walkthrough
First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:
Is it a graph?
- Yes: The throne inheritance system represents a family tree structure where each person (node) can have multiple children (edges). The relationships between family members form a graph structure.
Is it a tree?
- Yes: The family structure is specifically a tree because:
- There's one root (the king)
- Each person has exactly one parent (except the king)
- There are no cycles (you can't be your own ancestor)
- It's a hierarchical structure with parent-child relationships
DFS
- Conclusion: Since we have a tree structure, the flowchart directly leads us to use DFS (Depth-First Search).
This makes perfect sense for the throne inheritance problem because:
- We need to traverse the family tree starting from the king (root)
- The inheritance order follows a preorder traversal pattern - visit a person first, then recursively visit all their children in order
- DFS naturally handles the recursive nature of the inheritance rules (process parent → process oldest child → process that child's children → backtrack to process next sibling)
- The solution implements DFS through the recursive
dfs(x)
function that visits each node and its children in the correct inheritance order
The DFS approach perfectly captures the throne succession logic where we explore each branch of the family tree completely before moving to the next branch, which aligns with how inheritance naturally flows from parent to children before considering siblings.
Intuition
The key insight is recognizing that the throne inheritance order is essentially a preorder traversal of a family tree. When we think about how succession works in real life - the throne passes from parent to eldest child, then to that child's children before moving to younger siblings - this perfectly matches how we visit nodes in a preorder traversal.
Let's trace through why this makes sense. When determining who comes after person X in the inheritance order:
- If X has children who haven't been considered yet, the throne goes to their oldest unconsidered child
- If X has no children or all children have been considered, we need to backtrack to X's parent and find the parent's next child
This recursive backtracking pattern is exactly what happens naturally in a depth-first search. When we use DFS on a tree:
- We visit the current node (add the person to inheritance order if they're alive)
- We recursively visit all children in order (process all descendants)
- When we finish with all children, we automatically backtrack to the parent
The beauty of this approach is that we don't need to explicitly implement the complex Successor
function described in the problem. Instead, a simple DFS traversal automatically gives us the correct inheritance order. We just need to:
- Maintain a graph structure
g
where each parent maps to their list of children (preserving birth order) - Keep track of dead people in a set
dead
- When generating the inheritance order, do a DFS from the king, adding only living people to our result
The death mechanism is elegantly handled - we don't remove dead people from the tree structure (their children still need to inherit), we just skip them when building the final inheritance list. This way, the tree structure remains intact for traversal, but dead people are filtered out from the result.
Learn more about Tree and Depth-First Search patterns.
Solution Approach
The solution implements a preorder traversal of a multi-branch tree using depth-first search. Let's walk through the implementation details:
Data Structures Used:
- Hash Table (
self.g
): Adefaultdict(list)
that maps each parent's name to a list of their children's names. This represents the family tree structure where each person can have multiple children. - Set (
self.dead
): Stores the names of all dead people for O(1) lookup during traversal. - String (
self.king
): Stores the root of our tree (the king's name).
Implementation of Each Method:
__init__(self, kingName)
:
- Initializes the king as the root of the family tree
- Creates an empty graph
g
to store parent-child relationships - Creates an empty set
dead
to track deceased family members
birth(parentName, childName)
:
- Simply appends
childName
to the list of children forparentName
in the graph - The order of insertion matters as children are stored in birth order (oldest to youngest)
- Time complexity: O(1)
death(name)
:
- Adds the person's name to the
dead
set - Doesn't modify the tree structure - dead people's children can still inherit
- Time complexity: O(1)
getInheritanceOrder()
:
- Performs a DFS traversal starting from the king
- The inner
dfs(x)
function:- First checks if person
x
is alive usingx not in self.dead
- If alive, adds them to the answer list
- Then recursively visits all children of
x
in order
- First checks if person
- The traversal naturally follows preorder: visit node → visit all children left to right
- Returns the complete inheritance order excluding dead people
- Time complexity: O(n) where n is the total number of people in the family tree
The elegance of this solution lies in how the DFS traversal automatically handles the complex inheritance rules. By visiting nodes in preorder and maintaining children in birth order, we get the correct succession order without explicitly implementing the recursive Successor
function described in the problem.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to understand how the DFS approach naturally produces the correct inheritance order.
Initial Setup:
King has two children: Alice (older) and Bob (younger) Alice has one child: Carol Bob has two children: David (older) and Eve (younger)
Family Tree Structure:
King / \ Alice Bob | / \ Carol David Eve
Step 1: Building the Graph
After all births, our graph g
looks like:
g["King"] = ["Alice", "Bob"]
(children in birth order)g["Alice"] = ["Carol"]
g["Bob"] = ["David", "Eve"]
Step 2: DFS Traversal for Inheritance Order
Let's trace through the DFS starting from "King":
- Visit King: Add "King" to result →
["King"]
- Check King's children: ["Alice", "Bob"]
- Visit Alice (King's first child): Add "Alice" →
["King", "Alice"]
- Check Alice's children: ["Carol"]
- Visit Carol (Alice's child): Add "Carol" →
["King", "Alice", "Carol"]
- Carol has no children, backtrack to Alice
- Alice has no more children, backtrack to King
- Visit Bob (King's second child): Add "Bob" →
["King", "Alice", "Carol", "Bob"]
- Check Bob's children: ["David", "Eve"]
- Visit David (Bob's first child): Add "David" →
["King", "Alice", "Carol", "Bob", "David"]
- David has no children, backtrack to Bob
- Visit Eve (Bob's second child): Add "Eve" →
["King", "Alice", "Carol", "Bob", "David", "Eve"]
- Eve has no children, backtrack to Bob
- Bob has no more children, backtrack to King
- King has no more children, traversal complete
Final inheritance order: ["King", "Alice", "Carol", "Bob", "David", "Eve"]
Step 3: Handling Deaths
Now suppose Alice dies. We add "Alice" to the dead
set.
Running the same DFS traversal:
- Visit King → Add "King"
- Visit Alice → Skip (in
dead
set), but still traverse her children - Visit Carol → Add "Carol"
- Visit Bob → Add "Bob"
- Visit David → Add "David"
- Visit Eve → Add "Eve"
New inheritance order: ["King", "Carol", "Bob", "David", "Eve"]
Notice how Carol (Alice's daughter) still inherits even though Alice is dead. The throne would pass: King → Carol (granddaughter through deceased Alice) → Bob → David → Eve.
This demonstrates how the DFS approach elegantly handles both the succession rules and the death mechanism without complex logic - the tree traversal pattern naturally produces the correct order.
Solution Implementation
1from collections import defaultdict
2from typing import List
3
4class ThroneInheritance:
5 def __init__(self, kingName: str):
6 """
7 Initialize the throne inheritance system with the king's name.
8
9 Args:
10 kingName: The name of the king who is the root of the family tree
11 """
12 self.king = kingName
13 self.dead_people = set() # Set to track deceased people
14 self.family_tree = defaultdict(list) # Graph to store parent-child relationships
15
16 def birth(self, parentName: str, childName: str) -> None:
17 """
18 Record the birth of a child to a parent.
19
20 Args:
21 parentName: The name of the parent
22 childName: The name of the newborn child
23 """
24 self.family_tree[parentName].append(childName)
25
26 def death(self, name: str) -> None:
27 """
28 Mark a person as deceased.
29
30 Args:
31 name: The name of the person who died
32 """
33 self.dead_people.add(name)
34
35 def getInheritanceOrder(self) -> List[str]:
36 """
37 Get the current order of inheritance, excluding deceased people.
38
39 Returns:
40 List of names in the order of succession
41 """
42 def depth_first_search(person: str) -> None:
43 """
44 Traverse the family tree using DFS to build inheritance order.
45
46 Args:
47 person: Current person being visited in the tree
48 """
49 # Add person to result if they are alive
50 if person not in self.dead_people:
51 inheritance_order.append(person)
52
53 # Recursively visit all children
54 for child in self.family_tree[person]:
55 depth_first_search(child)
56
57 inheritance_order = []
58 depth_first_search(self.king)
59 return inheritance_order
60
61
62# Your ThroneInheritance object will be instantiated and called as such:
63# obj = ThroneInheritance(kingName)
64# obj.birth(parentName,childName)
65# obj.death(name)
66# param_3 = obj.getInheritanceOrder()
67
1class ThroneInheritance {
2 // The name of the king (root of the family tree)
3 private String king;
4
5 // Set to track deceased family members
6 private Set<String> deadPeople;
7
8 // Graph representation of family tree (parent -> list of children)
9 private Map<String, List<String>> familyTree;
10
11 // Temporary list to build inheritance order during DFS
12 private List<String> inheritanceOrder;
13
14 /**
15 * Initializes the throne inheritance system with the king's name
16 * @param kingName The name of the king
17 */
18 public ThroneInheritance(String kingName) {
19 this.king = kingName;
20 this.deadPeople = new HashSet<>();
21 this.familyTree = new HashMap<>();
22 this.inheritanceOrder = new ArrayList<>();
23 }
24
25 /**
26 * Records the birth of a child to a parent
27 * @param parentName The name of the parent
28 * @param childName The name of the newborn child
29 */
30 public void birth(String parentName, String childName) {
31 // Add child to parent's children list, creating the list if it doesn't exist
32 familyTree.computeIfAbsent(parentName, parent -> new ArrayList<>()).add(childName);
33 }
34
35 /**
36 * Records the death of a family member
37 * @param name The name of the deceased person
38 */
39 public void death(String name) {
40 deadPeople.add(name);
41 }
42
43 /**
44 * Returns the current order of inheritance excluding deceased members
45 * @return List of names in inheritance order
46 */
47 public List<String> getInheritanceOrder() {
48 // Clear previous results
49 inheritanceOrder.clear();
50
51 // Perform depth-first search starting from the king
52 performDFS(king);
53
54 return inheritanceOrder;
55 }
56
57 /**
58 * Helper method to perform depth-first search traversal of the family tree
59 * @param currentPerson The current person being visited in the traversal
60 */
61 private void performDFS(String currentPerson) {
62 // Add person to inheritance order only if they are alive
63 if (!deadPeople.contains(currentPerson)) {
64 inheritanceOrder.add(currentPerson);
65 }
66
67 // Recursively visit all children in order of birth
68 List<String> children = familyTree.getOrDefault(currentPerson, List.of());
69 for (String child : children) {
70 performDFS(child);
71 }
72 }
73}
74
75/**
76 * Your ThroneInheritance object will be instantiated and called as such:
77 * ThroneInheritance obj = new ThroneInheritance(kingName);
78 * obj.birth(parentName,childName);
79 * obj.death(name);
80 * List<String> param_3 = obj.getInheritanceOrder();
81 */
82
1class ThroneInheritance {
2public:
3 ThroneInheritance(string kingName) {
4 m_kingName = kingName;
5 }
6
7 void birth(string parentName, string childName) {
8 // Add child to parent's children list in the family tree
9 m_familyTree[parentName].push_back(childName);
10 }
11
12 void death(string name) {
13 // Mark person as deceased (they won't appear in inheritance order)
14 m_deceasedSet.insert(name);
15 }
16
17 vector<string> getInheritanceOrder() {
18 // Clear previous results and perform DFS traversal
19 m_inheritanceOrder.clear();
20 performDFS(m_kingName);
21 return m_inheritanceOrder;
22 }
23
24private:
25 string m_kingName; // Name of the king (root of family tree)
26 unordered_set<string> m_deceasedSet; // Set of deceased family members
27 unordered_map<string, vector<string>> m_familyTree; // Adjacency list representing parent-children relationships
28 vector<string> m_inheritanceOrder; // Result vector for inheritance order
29
30 void performDFS(const string& currentPerson) {
31 // Add person to inheritance order only if they are alive
32 if (m_deceasedSet.find(currentPerson) == m_deceasedSet.end()) {
33 m_inheritanceOrder.push_back(currentPerson);
34 }
35
36 // Recursively process all children in birth order
37 if (m_familyTree.find(currentPerson) != m_familyTree.end()) {
38 for (const string& child : m_familyTree[currentPerson]) {
39 performDFS(child);
40 }
41 }
42 }
43};
44
45/**
46 * Your ThroneInheritance object will be instantiated and called as such:
47 * ThroneInheritance* obj = new ThroneInheritance(kingName);
48 * obj->birth(parentName,childName);
49 * obj->death(name);
50 * vector<string> param_3 = obj->getInheritanceOrder();
51 */
52
1// Global variables for throne inheritance system
2let king: string;
3let deadPeople: Set<string> = new Set();
4let familyTree: Map<string, string[]> = new Map();
5
6/**
7 * Initializes the throne inheritance system with the king's name
8 * @param kingName - The name of the king who is the root of the inheritance tree
9 */
10function ThroneInheritance(kingName: string): void {
11 king = kingName;
12 deadPeople = new Set();
13 familyTree = new Map();
14}
15
16/**
17 * Records the birth of a child to a parent in the family tree
18 * @param parentName - The name of the parent
19 * @param childName - The name of the newborn child
20 */
21function birth(parentName: string, childName: string): void {
22 // Initialize parent's children array if it doesn't exist
23 if (!familyTree.has(parentName)) {
24 familyTree.set(parentName, []);
25 }
26 // Add the child to the parent's children list
27 familyTree.get(parentName)!.push(childName);
28}
29
30/**
31 * Marks a person as deceased (they will be excluded from inheritance order)
32 * @param name - The name of the person who has died
33 */
34function death(name: string): void {
35 deadPeople.add(name);
36}
37
38/**
39 * Returns the current order of inheritance excluding deceased members
40 * Uses depth-first search to traverse the family tree in preorder
41 * @returns Array of names in inheritance order
42 */
43function getInheritanceOrder(): string[] {
44 const inheritanceOrder: string[] = [];
45
46 /**
47 * Recursive helper function to perform DFS traversal
48 * @param currentPerson - The current person being visited in the tree
49 */
50 const performDFS = (currentPerson: string): void => {
51 // Add person to inheritance order only if they are alive
52 if (!deadPeople.has(currentPerson)) {
53 inheritanceOrder.push(currentPerson);
54 }
55
56 // Recursively visit all children in birth order
57 const children = familyTree.get(currentPerson) || [];
58 for (const child of children) {
59 performDFS(child);
60 }
61 };
62
63 // Start DFS from the king (root of the tree)
64 performDFS(king);
65 return inheritanceOrder;
66}
67
Time and Space Complexity
Time Complexity:
-
__init__(self, kingName)
:O(1)
- Simply initializes the king name, creates an empty set for dead people, and creates an empty defaultdict for the graph. -
birth(self, parentName, childName)
:O(1)
- Appends a child to the parent's list in the graph dictionary, which is a constant time operation. -
death(self, name)
:O(1)
- Adds a name to the dead set, which is a constant time operation in Python. -
getInheritanceOrder(self)
:O(n)
wheren
is the total number of people in the inheritance tree. The DFS traversal visits each person exactly once, and for each person, it performs constant time operations (checking if they're in the dead set and appending to the result list if not).
Space Complexity:
- Overall space complexity:
O(n)
wheren
is the total number of people in the inheritance system.- The graph
self.g
stores all parent-child relationships:O(n)
space for storing all people and their children. - The
self.dead
set stores deceased people:O(d)
space whered ≤ n
is the number of dead people. - During
getInheritanceOrder()
, the recursion stack can go as deep as the height of the tree, which in the worst case (a linear chain) isO(n)
. - The
ans
list ingetInheritanceOrder()
stores at mostn
people:O(n)
space.
- The graph
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Handling of Dead People in the Tree Structure
Pitfall: A common mistake is to remove dead people from the family tree structure when they die. This would break the inheritance chain for their descendants.
# WRONG approach
def death(self, name: str) -> None:
# Don't do this - it breaks the tree structure!
del self.family_tree[name]
self.dead_people.add(name)
Why it's wrong: Dead people's children should still be able to inherit. If we remove the dead person from the tree, we lose the connection to their descendants.
Correct Solution: Keep dead people in the tree structure but filter them out during traversal:
def death(self, name: str) -> None:
# Only mark as dead, don't modify tree structure
self.dead_people.add(name)
2. Using BFS Instead of DFS for Traversal
Pitfall: Using breadth-first search would give incorrect inheritance order because it processes all nodes at the same level before moving to the next level.
# WRONG - BFS gives incorrect order
def getInheritanceOrder(self) -> List[str]:
from collections import deque
queue = deque([self.king])
result = []
while queue:
person = queue.popleft()
if person not in self.dead_people:
result.append(person)
queue.extend(self.family_tree[person])
return result # This gives level-order, not inheritance order!
Example showing the difference:
- Tree: King → Alice, Bob; Alice → Jack
- BFS order: [King, Alice, Bob, Jack] ❌
- DFS order: [King, Alice, Jack, Bob] ✅
Correct Solution: Use DFS (preorder traversal) to ensure we fully explore each branch before moving to siblings.
3. Not Preserving Birth Order of Children
Pitfall: Using a data structure that doesn't preserve insertion order for children, or sorting children alphabetically.
# WRONG - Using a set loses birth order
def __init__(self, kingName: str):
self.family_tree = defaultdict(set) # Sets don't preserve order!
# WRONG - Sorting children alphabetically
def getInheritanceOrder(self) -> List[str]:
def dfs(person):
if person not in self.dead_people:
result.append(person)
# Don't sort! Birth order matters
for child in sorted(self.family_tree[person]):
dfs(child)
Why it matters: The inheritance order depends on birth order (oldest to youngest), not alphabetical order.
Correct Solution: Use a list to maintain insertion order:
self.family_tree = defaultdict(list) # Lists preserve insertion order
4. Forgetting to Handle People with No Children
Pitfall: Not using defaultdict
or not checking if a person exists in the dictionary before accessing their children.
# WRONG - KeyError for people with no children
def getInheritanceOrder(self) -> List[str]:
def dfs(person):
if person not in self.dead_people:
result.append(person)
# This fails if person has no children!
for child in self.family_tree[person]:
dfs(child)
Correct Solution: Use defaultdict(list)
which automatically returns an empty list for missing keys, or check existence:
# Option 1: defaultdict handles it automatically
self.family_tree = defaultdict(list)
# Option 2: Check before accessing
if person in self.family_tree:
for child in self.family_tree[person]:
dfs(child)
Consider the classic dynamic programming of longest increasing subsequence:
Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.
For example, the length of LIS for [50, 3, 10, 7, 40, 80]
is 4
and LIS is
[3, 7, 40, 80]
.
What is the recurrence relation?
Recommended Readings
Everything About Trees A tree is a type of graph data structure composed of nodes and edges Its main properties are It is acyclic doesn't contain any cycles There exists a path from the root to any node Has N 1 edges where N is the number of nodes in the tree and
https assets algo monster cover_photos dfs svg Depth First Search Prereqs Recursion Review problems recursion_intro Trees problems tree_intro With a solid understanding of recursion under our belts we are now ready to tackle one of the most useful techniques in coding interviews Depth First Search DFS As the name suggests
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!