Facebook Pixel

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:

  1. Constructor ThroneInheritance(kingName): Initialize the system with the king's name
  2. birth(parentName, childName): Record that parentName had a child named childName
  3. death(name): Mark a person as dead (they should be excluded from the inheritance order but their descendants can still inherit)
  4. 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:

  1. We need to traverse the family tree starting from the king (root)
  2. The inheritance order follows a preorder traversal pattern - visit a person first, then recursively visit all their children in order
  3. 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)
  4. 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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. We visit the current node (add the person to inheritance order if they're alive)
  2. We recursively visit all children in order (process all descendants)
  3. 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:

  1. Hash Table (self.g): A defaultdict(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.
  2. Set (self.dead): Stores the names of all dead people for O(1) lookup during traversal.
  3. 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 for parentName 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 using x not in self.dead
    • If alive, adds them to the answer list
    • Then recursively visits all children of x in order
  • 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 Evaluator

Example 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":

  1. Visit King: Add "King" to result → ["King"]
    • Check King's children: ["Alice", "Bob"]
  2. Visit Alice (King's first child): Add "Alice" → ["King", "Alice"]
    • Check Alice's children: ["Carol"]
  3. 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
  4. Visit Bob (King's second child): Add "Bob" → ["King", "Alice", "Carol", "Bob"]
    • Check Bob's children: ["David", "Eve"]
  5. Visit David (Bob's first child): Add "David" → ["King", "Alice", "Carol", "Bob", "David"]
    • David has no children, backtrack to Bob
  6. 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:

  1. Visit King → Add "King"
  2. Visit Alice → Skip (in dead set), but still traverse her children
  3. Visit Carol → Add "Carol"
  4. Visit Bob → Add "Bob"
  5. Visit David → Add "David"
  6. 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) where n 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) where n 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 where d ≤ 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) is O(n).
    • The ans list in getInheritanceOrder() stores at most n people: O(n) space.

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)
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More