1516. Move Sub-Tree of N-Ary Tree
Problem Explanation
This problem involves dealing with an N-ary tree where each node can have N children. We have the root of the tree and two nodes, p
and q
. The task is to move the subtree of node p
, under node q
. Node p
should become the last child of node q
.
There are three scenarios to consider:
- Node
q
is in the subtree of nodep
. - Node
p
is in the subtree of nodeq
. - Neither node
p
norq
lie in each other's subtree.
For the second and third cases, the problem is straightforward - move p
(with its subtree) to be a child of q
. But in the first case, doing so may disconnect the tree. Therefore, we must reconnect the tree again. In this case, we first move p
with all of its subtree except q
and add it as a child to q
. Then we see if the tree is disconnected and reconnect it accordingly.
Walkthrough
Let's take an example where our input tree is [1,null,2,3,null,4,5,null,6,null,7,8]
, p
equals 2
and q
equals 7
. This example falls under the first case where q
is in the subtree of p
.
First step: We move p
(with all of its subtree except q
) and add it as a child to q
. This gives us a tree [1,null,7,3,null,2,null,6,null,4,5,null,null,8]
.
Then we notice that the tree is disconnected so we need to reconnect q
to replace p
.
Approach
-
The first step in the solution is checking if
p
already is a child ofq
. In this case, we don't have to do anything. -
We add a dummy node to handle the case where
p
is the root of the tree. -
We get the parent of
p
and remove it from its children list. -
Add
p
as a child toq
. -
We check if
q
is in the subtree ofp
. If it is, we have to also updateq
's parent to replaceq
withp
.
Python Solution
python class Solution: def moveSubTree(self, root, p, q): if p in q.children: return root dummy = Node(0, [root]) pParent = self.getParent(dummy, p) pParent.children.remove(p) q.children.append(p) qParent = self.getParent(p, q) if qParent: qParent.children.remove(q) pParent.children.append(q) return dummy.children[0] def getParent(self, root, node): stack = [(root, None)] while stack: curr, parent = stack.pop() if curr == node: return parent for child in curr.children: stack.append((child, curr)) return None
Java Solution
java
public class Solution {
public Node moveSubTree(Node root, Node p, Node q) {
if (q.children.contains(p)) {
return root;
}
Node dummy = new Node(0, Arrays.asList(root));
Node pParent = getParent(dummy, p);
pParent.children.remove(p);
q.children.add(p);
Node qParent = getParent(p, q);
if (qParent != null) {
qParent.children.remove(q);
pParent.children.add(q);
}
return dummy.children.get(0);
}
private Node getParent(Node root, Node target) {
Deque<Pair<Node, Node>> stack = new ArrayDeque<>();
stack.push(new Pair(root, null));
while (!stack.isEmpty()) {
Pair<Node, Node> curr = stack.pop();
if (curr.getKey() == target) {
return curr.getValue();
}
for (Node child: curr.getKey().children) {
stack.push(new Pair(child, curr.getKey()));
}
}
return null;
}
}
C# Solution
csharp
public class Solution {
public Node MoveSubTree(Node root, Node p, Node q) {
if (q.children.Contains(p)) {
return root;
}
Node dummy = new Node(0, new List<Node> {root});
Node pParent = GetParent(dummy, p);
pParent.children.Remove(p);
q.children.Add(p);
Node qParent = GetParent(p, q);
if (qParent != null) {
qParent.children.Remove(q);
pParent.children.Add(q);
}
return dummy.children[0];
}
private Node GetParent(Node root, Node target) {
Stack<Tuple<Node, Node>> stack = new Stack<Tuple<Node, Node>>();
stack.Push(new Tuple<Node, Node>(root, null));
while (stack.Count > 0) {
Tuple<Node, Node> curr = stack.Pop();
if (curr.Item1 == target) {
return curr.Item2;
}
foreach (Node child in curr.Item1.children) {
stack.Push(new Tuple<Node, Node>(child, curr.Item1));
}
}
return null;
}
}
JavaScript Solution
javascript
class Solution {
moveSubTree(root, p, q){
if(q.children.includes(p)){
return root;
}
let dummy = {val: 0, children: [root]};
let pParent = this.getParent(dummy, p);
pParent.children = pParent.children.filter(child => child !== p);
q.children.push(p);
let qParent = this.getParent(p, q);
if(qParent){
qParent.children = qParent.children.filter(child => child !== q);
pParent.children.push(q);
}
return dummy.children[0];
}
getParent(root, target){
let stack = [[root, null]];
while(stack.length){
let [node, parent] = stack.pop();
if(node === target){
return parent;
}
for(let child of node.children){
stack.push([child, node]);
}
}
return null;
}
}
C++ Solution
cpp
class Solution{
public:
Node* moveSubTree(Node* root, Node* p, Node* q){
if(find(q->children.begin(), q->children.end(), p) != q->children.end()){
return root;
}
Node* dummy = new Node(0, {root});
Node* pParent = getParent(dummy, p);
pParent->children.erase(remove(pParent->children.begin(), pParent->children.end(), p), pParent->children.end());
q->children.push_back(p);
Node* qParent = getParent(p, q);
if(qParent){
qParent->children.erase(remove(qParent->children.begin(), qParent->children.end(), q), qParent->children.end());
pParent->children.push_back(q);
}
return dummy->children[0];
}
private:
Node* getParent(Node* root, Node* target){
stack<pair<Node*, Node*>> stk;
stk.push({root, nullptr});
while(!stk.empty()){
auto [node, parent] = stk.top();
stk.pop();
if(node == target){
return parent;
}
for(auto& child : node->children){
stk.push({child, node});
}
}
return nullptr;
}
};
In this C++ solution, we start by checking if p
is already a child of q
. If it is, we simply return the root as no moving is needed.
We then create a dummy node and add root
to it. We find the parent of p
and remove p
from its children. We push p
into q
's children.
Finally, we find if q
is present in the subtree of p
. If it is, we find the parent of q
and remove q
from its children and add q
to pParent's
children.
This way, we have moved the subtree rooted at p
to become the last child of q
.
The method getParent
finds the parent of the target node by DFS (Depth-First Search) using a stack, which stores pairs of current nodes and their parents. If it finds the target node in the stack, it pops and returns the parent. If it doesn't find the target, it returns nullptr
.
It returns the new root
.
This solution assumes that nodes of the tree hold unique values.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorWhich algorithm should you use to find a node that is close to the root of the tree?
Recommended Readings
LeetCode 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 we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!