# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def flipEquiv(self, root1: TreeNode, root2: TreeNode) -> bool:
if not root1 and not root2:
return True
if not root1 or not root2 or root1.val != root2.val:
return False
return (
(self.flipEquiv(root1.left, root2.left) and self.flipEquiv(root1.right, root2.right)) or
(self.flipEquiv(root1.left, root2.right) and self.flipEquiv(root1.right, root2.left))
)
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
bool flipEquiv(TreeNode* root1, TreeNode* root2) {
if (!root1 && !root2) return true;
if (!root1 || !root2 || root1->val != root2->val) return false;
return (flipEquiv(root1->left, root2->left) && flipEquiv(root1->right, root2->right)) ||
(flipEquiv(root1->left, root2->right) && flipEquiv(root1->right, root2->left));
}
};
// Definition for a binary tree node.
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
public boolean flipEquiv(TreeNode root1, TreeNode root2) {
if (root1 == null && root2 == null) return true;
if (root1 == null || root2 == null || root1.val != root2.val) return false;
return (flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right)) ||
(flipEquiv(root1.left, root2.right) && flipEquiv(root1.right, root2.left));
}
}
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root1
* @param {TreeNode} root2
* @return {boolean}
*/
var flipEquiv = function(root1, root2) {
if (!root1 && !root2) return true;
if (!root1 || !root2 || root1.val !== root2.val) return false;
return (
(flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right)) ||
(flipEquiv(root1.left, root2.right) && flipEquiv(root1.right, root2.left))
);
};
Given two binary trees represented by their root nodes root1
and root2
, determine if they are flip equivalent. Two binary trees are flip equivalent if they are the same when you are allowed to flip (swap) the left and right children of any number of nodes in either tree.
null
).
The goal is to return True
if the trees are flip equivalent, and False
otherwise.
At first, you might think to compare the two trees node by node, checking if the left and right children match. However, because we can flip any subtree, a simple traversal won't work. Instead, we need to consider both the original and the flipped configuration at each node.
The key insight is that for two nodes to be flip equivalent, their values must match, and their children must be flip equivalent in either the original or flipped order. This means that at each step, we need to check both possible pairings of children.
A brute-force approach would try all possible sequences of flips, but this quickly becomes infeasible as the tree grows. Instead, we use recursion to check both possibilities at each node, which is much more efficient and elegant.
null
, they are trivially equivalent. Return True
.null
, or their values differ, they can't be equivalent. Return False
.root1
is flip equivalent to the left child of root2
and the right child of root1
is flip equivalent to the right child of root2
(no flip at this node).root1
is flip equivalent to the right child of root2
and the right child of root1
is flip equivalent to the left child of root2
(flipped at this node).This recursive approach naturally explores all valid flip combinations without redundant work, since at each node we only consider two configurations.
Let's look at an example:
Tree 1: 1 / \ 2 3 / / \ 4 5 6 Tree 2: 1 / \ 3 2 / \ \ 6 5 4
The flip equivalent binary trees problem asks whether two trees can be made identical by flipping any number of left and right children. The elegant recursive solution checks, at each node, both the original and flipped child pairings. This approach is efficient, with linear time complexity, and avoids the combinatorial explosion of brute-force methods. The key insight is that flip equivalence is a local property at each pair of nodes, making recursion a natural fit for the problem.