Reputation: 1
I am struggling with a Java exercise.
I am given an array of tree nodes. Each tree node has a parenting, and a int value. I am also given an int, which represents a node value. I am asked to delete the subtree from the array where the value given is the root of the subtree.
I am thinking the best approach might be to create an arraylist, and iterate through the input array, adding the nodes I am keeping to the arraylist, and then convert that arraylist to an array.
I am struggling with determining the best way to delete all of the subtree roots children since I only have parentId.
Am I on the right track?
Upvotes: 0
Views: 941
Reputation: 4719
Here's an algorithm you can use:
Time complexity = O(n) Space complexity = O(n)
Upvotes: 0
Reputation: 5455
If you're allowed to update Nodes
before purging them a simple approach would be to iterate through the array and use a recursive function to follow the path from each node to the root or a parent whose data matches the query data. In the latter case we update the data of all nodes on the path to the query value. Then, in a 2nd pass through the array we compress it, removing nodes whose value matches the query.
Here's some Java code to illustrate:
static int clearPath(Node[] arr, int query)
{
for(int i=0; i<arr.length; i++)
if(arr[i].data != query)
markPath(arr[i], query);
int j = 0;
for(int i=0; i<arr.length; i++)
if(arr[i].data != query)
arr[j++] = arr[i];
return j;
}
static boolean markPath(Node node, int query)
{
if(node == null) return false;
if(node.data == query) return true;
boolean located = markPath(node.parent, query);
if(located) node.data = query;
return located;
}
And the Node
class:
static class Node
{
Node parent;
int data;
public Node(Node parent, int data)
{
this.parent = parent;
this.data = data;
}
public String toString()
{
return String.format("(%d : %s) ", data, (parent == null ? "*" : parent.data));
}
}
Test:
int[][] tree = {{1, 2, 3, 4}, {2, 3, 4, 5}, {5, 6, 7}};
List<Node> nodeList = new ArrayList<>();
for(int[] sub : tree)
{
Node node = null;
for(int data : sub)
nodeList.add(node = new Node(node, data));
}
Node[] arr = nodeList.toArray(new Node[nodeList.size()]);
System.out.println(Arrays.toString(arr));
int n = clearPath(arr, 3);
System.out.println(Arrays.toString(Arrays.copyOfRange(arr, 0, n)));
Output:
[(1 : *) , (2 : 1) , (3 : 2) , (4 : 3) , (2 : *) , (3 : 2) , (4 : 3) , (5 : 4) , (5 : *) , (6 : 5) , (7 : 6) ]
[(1 : *) , (2 : 1) , (2 : *) , (5 : *) , (6 : 5) , (7 : 6) ]
If you're not allowed to update node data you could use a Set
to hold nodes to be removed.
static int clearPath2(Node[] arr, int query)
{
Set<Node> rem = new HashSet<>();
for(int i=0; i<arr.length; i++)
markPath2(rem, arr[i], query);
int j = 0;
for(int i=0; i<arr.length; i++)
if(!rem.contains(arr[i])) arr[j++] = arr[i];
return j;
}
static boolean markPath2(Set<Node> rem, Node node, int query)
{
if(node == null) return false;
if(node.data == query || markPath2(rem, node.parent, query))
{
rem.add(node);
return true;
}
return false;
}
Upvotes: 0
Reputation: 18255
This solution does not give you the best performance, because it iterates over the given array multiple times, but it's pretty simple.
public class MavenMain {
public static final class Node {
private final int id;
private final Integer parentId;
private final int val;
public Node(int id, Integer parentId, int val) {
this.id = id;
this.parentId = parentId;
this.val = val;
}
}
public static void main(String... args) {
/*
* 1
* / \
* 2 5
* / \ / \
* 3 4 6 7
*/
Node[] nodes = {
new Node(11, null, 1),
new Node(22, 11, 2), new Node(55, 11, 5),
new Node(33, 22, 3), new Node(44, 22, 4), new Node(66, 55, 6), new Node(77, 55, 7) };
Node[] res = removeSubtree(nodes, 1); // remove root is 2
}
public static Node[] removeSubtree(Node[] nodes, int subTreeRoot) {
Node removeRoot = nodes[subTreeRoot];
if (removeRoot.parentId == null) // this is a root, i.e. remove whole tree
return new Node[0];
Set<Integer> removedNodes = new HashSet<>();
removedNodes.add(removeRoot.id);
while (true) {
boolean found = false;
for (int i = 0; i < nodes.length; i++) {
if (removedNodes.contains(nodes[i].id) || !removedNodes.contains(nodes[i].parentId))
continue;
removedNodes.add(nodes[i].id);
found = true;
}
if (!found)
break;
}
Node[] res = new Node[nodes.length - removedNodes.size()];
for (int i = 0, j = 0; i < nodes.length; i++)
if (!removedNodes.contains(nodes[i].id))
res[j++] = nodes[i];
return res;
}
}
Upvotes: 0
Reputation: 36
Are you given the root of the tree nodes? If so just traverse the tree. Once you hit the node value to be deleted, just remove the link of the previous node from the node to be deleted.
This link explains it- Remove Subtree with specific value
Upvotes: 0