You are given an undirected tree with n nodes, numbered from 0 to n - 1. It is represented by a 2D integer array edges of length n - 1, where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the tree.
You are also given two binary strings start and target of length n. For each node x, start[x] is its initial color and target[x] is its desired color.
In one operation, you may pick an edge with index i and toggle both of its endpoints. That is, if the edge is [u, v], then the colors of nodes u and veach flip from '0' to '1' or from '1' to '0'.
Return an array of edge indices whose operations transform start into target. Among all valid sequences with minimum possible length, return the edge indices in increasing order.
If it is impossible to transform start into target, return an array containing a single element equal to -1.
There is no sequence of edge toggles that transforms "00" into "01". Therefore, we return [-1].
Constraints:
2 <= n == start.length == target.length <= 105
edges.length == n - 1
edges[i] = [ai, bi]
0 <= ai, bi < n
start[i] is either '0' or '1'.
target[i] is either '0' or '1'.
The input is generated such that edges represents a valid tree.
Solutions
Solution 1: DFS
Thinking
Toggling an edge flips both endpoints. \(n \le 10^5\) rules out subset search. On a tree the need inside a subtree is determined bottom-up.
A leaf that mismatches the target must toggle the edge to its parent, which then flips the parent's remaining need, so the demand travels upward.
DFS returns whether the subtree still needs the parent edge: each chosen child edge negates the current node's demand.
If the root still needs a flip, there is no solution; otherwise the sorted chosen edge indices form a shortest valid sequence.
We define an adjacency list \(g\) to represent the tree, where \(g[a]\) stores all adjacent nodes of node \(a\) and the indices of the corresponding edges.
We design a function \(\text{dfs}(a, \text{fa})\), which indicates whether the edge between node \(a\) and \(\text{fa}\) needs to be toggled in the subtree rooted at node \(a\) with parent \(\text{fa}\). The logic of the function \(\text{dfs}(a, \text{fa})\) is as follows:
Initialize a boolean variable \(\text{rev}\), indicating whether node \(a\) needs to be toggled. The initial value is \(\text{start}[a] \ne \text{target}[a]\).
Iterate through all adjacent nodes \(b\) of node \(a\) and the corresponding edge index \(i\):
If \(b \ne \text{fa}\), recursively call \(\text{dfs}(b, a)\).
If the recursive call returns true, it means the edge \([a, b]\) in the subtree needs to be toggled. We add the edge index \(i\) to the answer list and toggle \(\text{rev}\).
Return \(\text{rev}\).
Finally, we call \(\text{dfs}(0, -1)\). If the return value is true, it means it is impossible to convert \(\text{start}\) to \(\text{target}\), so we return \([-1]\). Otherwise, we sort the answer list and return it.
The time complexity is \(O(n \times \log n)\), and the space complexity is \(O(n)\). Here, \(n\) is the number of nodes in the tree.
Toggling an edge flips both endpoints. \(n\) can reach \(10^5\), so searching subsets of edges is impossible. On a chain the first recursive call always follows the only child, so the depth is \(n\) and exceeds the default recursion limit.
A leaf that mismatches the target must toggle the edge to its parent. That demand is known only after the whole subtree has been finished.
An explicit stack walks the tree in postorder. On entry, push the exit marker and then the children. On exit, start from whether the node differs from the target; each child edge that must be toggled negates that demand and is recorded.
If the root still needs a flip, there is no solution; otherwise the sorted chosen edge indices form a shortest valid sequence.
We define an adjacency list \(g\) to represent the tree, where \(g[a]\) stores all adjacent nodes of node \(a\) and the indices of the corresponding edges.
An explicit stack walks the tree from node \(0\) in postorder. Entering a node pushes that node's exit marker and then its children, so the children finish first. On exit, \(\text{rev}\) records whether the edge from the current node to its parent still needs a toggle. It starts as \(\text{start}[a] \ne \text{target}[a]\). For each child \(b\), if that subtree still needs the edge \([a, b]\) toggled, append the edge index \(i\) and negate \(\text{rev}\). The root has no parent. If the root's \(\text{rev}\) is still true, converting \(\text{start}\) to \(\text{target}\) is impossible and the result is \([-1]\). Otherwise sort the answer and return it.
The time complexity is \(O(n \times \log n)\), and the space complexity is \(O(n)\). Here, \(n\) is the number of nodes in the tree.