{x}
blog image

Flip Binary Tree To Match Preorder Traversal

You are given the root of a binary tree with n nodes, where each node is uniquely assigned a value from 1 to n. You are also given a sequence of n values voyage, which is the desired pre-order traversal of the binary tree.

Any node in the binary tree can be flipped by swapping its left and right subtrees. For example, flipping node 1 will have the following effect:

Flip the smallest number of nodes so that the pre-order traversal of the tree matches voyage.

Return a list of the values of all flipped nodes. You may return the answer in any order. If it is impossible to flip the nodes in the tree to make the pre-order traversal match voyage, return the list [-1].

 

Example 1:

Input: root = [1,2], voyage = [2,1]
Output: [-1]
Explanation: It is impossible to flip the nodes such that the pre-order traversal matches voyage.

Example 2:

Input: root = [1,2,3], voyage = [1,3,2]
Output: [1]
Explanation: Flipping node 1 swaps nodes 2 and 3, so the pre-order traversal matches voyage.

Example 3:

Input: root = [1,2,3], voyage = [1,2,3]
Output: []
Explanation: The tree's pre-order traversal already matches voyage, so no nodes need to be flipped.

 

Constraints:

  • The number of nodes in the tree is n.
  • n == voyage.length
  • 1 <= n <= 100
  • 1 <= Node.val, voyage[i] <= n
  • All the values in the tree are unique.
  • All the values in voyage are unique.

Solution Explanation: Flip Binary Tree To Match Preorder Traversal

This problem asks us to find the minimum number of node flips in a binary tree to match a given preorder traversal (voyage). We achieve this using Depth-First Search (DFS).

Approach:

The core idea is to recursively traverse the tree, comparing the current node's value with the next expected value in the voyage array. If they match, we proceed; otherwise, we attempt to flip the current node to see if that allows us to continue matching the voyage.

  1. DFS Traversal: We employ a recursive DFS function. The function takes the current node as input.

  2. Value Check: The first thing we do is check if the current node's value (root.val) matches the next expected value (voyage[i]). If not, it's impossible to match the voyage, so we set a boolean flag (ok) to false and return.

  3. Left/Right Child Check: If the values match, we increment the index i. Then we check the left child.

    • No Flip Needed: If there is no left child or the left child's value matches voyage[i], we recursively call dfs on the left and then the right child.
    • Flip Required: If the left child's value doesn't match voyage[i], we need to flip the current node. This means we add the current node's value to our ans array (list of flipped nodes), and then recursively call dfs on the right child (which becomes the new "left" after the flip) and then the left child (which becomes the new "right" after the flip).
  4. Return Value: After the traversal, if ok is still true, we return the ans array. Otherwise (if we encountered a mismatch and set ok to false), we return [-1], indicating that it's not possible to match the voyage with any number of flips.

Time Complexity Analysis:

The DFS function visits each node in the tree exactly once. Therefore, the time complexity is O(N), where N is the number of nodes in the tree.

Space Complexity Analysis:

The space complexity is determined by the recursive call stack. In the worst-case scenario (a skewed tree), the depth of the recursion can be N. Therefore, the space complexity is O(N) in the worst case. In the average case (a balanced tree), it would be O(log N).

Code Examples (Python, Java, C++, Go, TypeScript):

The code examples in the problem description clearly demonstrate the implementation of the described algorithm in multiple languages. Each example follows the same logical steps outlined in the approach section. They are well-commented and easy to follow.

Example Walkthrough (Example 2):

root = [1, 2, 3], voyage = [1, 3, 2]

  1. DFS starts at node 1. root.val (1) matches voyage[0] (1). i increments to 1.
  2. Node 1's left child (2) doesn't match voyage[1] (3). We flip node 1. Add 1 to ans.
  3. Recursively call DFS on the right child (3) first. This matches voyage[1] (3).
  4. Then, recursively call DFS on the left child (2). This matches voyage[2] (2).
  5. The traversal completes successfully. ans contains [1]. The function returns [1].

This detailed explanation along with the provided code examples covers the solution comprehensively.