0

How to use BFS or DFS to get all cousins of a given node and add into an ArrayList. If anyone can help point out where my logic is wrong

static boolean findLevel(Node root, Node find, int level) {
    boolean status = false;

    if (root == null || find == null)
        return false;

    if (root == find)
        status = true;

    findLevel(root.left, find, level + 1);
    findLevel(root.right, find, level + 1);

    return status;
}

static boolean sibling(Node root, Node find) {
    boolean status = false;

    if (root == null || find == null)
        return false;

    if (root.left == find && root.right == find)
        status = true;

    sibling(root.left, find);
    sibling(root.right, find);

    return status;

}

enter image description here

SEJU
  • 33
  • 8
  • Which method is called first? If you don't mind, can you share the exact problem statement with sample I/Os? – nice_dev Jan 23 '22 at 18:10
  • I am comparing findLevel with siblings in the method printCousins. I also attached the exact question if what you mean by "can you share the exact problem statement..." above. @nice_dev – SEJU Jan 23 '22 at 18:23
  • Yes, this makes sense now. Question seems complete. – nice_dev Jan 23 '22 at 18:33
  • Could you please spend a couple of minutes of your time evaluating the answers and also accept the best one. It wasn't the easiest question, give us a favor – Alexander Ivanchenko Jan 24 '22 at 19:43
  • I sure will @AlexanderIvanchenko – SEJU Jan 24 '22 at 21:11

3 Answers3

0

In your approach, you seem to assume that cousins can have only 1 different parent. The more we go deeper, the more the different parents for a particular find node or you can say the more the cousins. Also, if(root.left == find && root.right == find){ doesn't make sense since there can't be 2 same nodes in the tree, especially with find.


In your printCousins, you will need to find the level of the find node and then collect all it's cousins by passing it to siblings method.

public static ArrayList<Integer> printCousins(Node root, Node find){
    //code here
    ArrayList<Integer> arr = new ArrayList<>();
    int level = findLevel(root, find, 0);
    if(level == -1){
        arr.add(-1);
        return arr;
    }

    siblings(root, find, arr, 0, level);
    if(arr.isEmpty()){
        arr.add(-1);
    }
    return arr;
}

Since you use depth first search technique, you can find the level of the find node first like below:

 static int findLevel(Node root, Node find, int level){
    if(root == null) return -1;
    if(root == find) return level;
    
    int l = findLevel(root.left, find, level + 1);
    if(l == -1) l = findLevel(root.right, find, level + 1);// only go to the right side of the node if not found on the left part
    
    return l;
}

In siblings, you will add all those nodes to arr that are located at level with a careful check of the parent not having find as one of their kids thereby ensuring different parents same level requirement.

static void siblings(Node root, Node find, ArrayList<Integer> arr, int curr_level, int level){
    if(root == null || curr_level > level || root == find) return;
    if(curr_level + 1 == level){
        if(root.left == find || root.right == find) return; // making sure either of the kids isn't 'find'
    }

    if(curr_level == level){
        arr.add(root.val);
        return;
    }
    
    siblings(root.left, find, arr, curr_level + 1, level);
    siblings(root.right, find, arr, curr_level + 1, level);
}
nice_dev
  • 17,053
  • 2
  • 21
  • 35
0

I can see in this task is simple BFS - Breadth-first search. All you need is to find a level where your target node and print all other nodes at the same level with different parents, which could be quite easy if you keep the parent of each node (I offer to do this with the additional class NodeWithParent).

// This is a class you have to provide a Tree
public static class Node {

    private final int value;
    private Node left;
    private Node right;

    public Node(int value) {
        this.value = value;
    }

}

// This is an internal class to keep the node's parent
private static class NodeWithParent {

    private final Node delegate;
    private final Integer parent;

    public NodeWithParent(Node delegate, Integer parent) {
        this.delegate = delegate;
        this.parent = parent;
    }

}

public static Set<Integer> printCousins(Node root, int find) {
    NodeWithParent tmp = new NodeWithParent(root, null);
    Deque<NodeWithParent> levelNodes = new LinkedList<>();
    levelNodes.add(tmp);

    // not null means target node was found at current level
    NodeWithParent findNode = root.value == find ? tmp : null;

    while (!levelNodes.isEmpty()) {
        if (findNode != null)
            return getNodesNotForParent(levelNodes, findNode);

        int total = levelNodes.size();

        for (int i = 0; i < total; i++) {
            NodeWithParent node = levelNodes.remove();
            NodeWithParent findNode1 = addNotNullChild(node.delegate.left, node.delegate.value, find, levelNodes);
            NodeWithParent findNode2 = addNotNullChild(node.delegate.right, node.delegate.value, find, levelNodes);

            if (findNode == null)
                findNode = findNode1 == null ? findNode2 : findNode1;
        }
    }

    return Set.of();
}

private static NodeWithParent addNotNullChild(Node childNode, int parentValue, int find, Deque<NodeWithParent> levelNodes) {
    if (childNode == null)
        return null;
    
    NodeWithParent node = new NodeWithParent(childNode, parentValue);
    levelNodes.add(node);
    return childNode.value == find ? node : null;
}

private static Set<Integer> getNodesNotForParent(Collection<NodeWithParent> nodes, NodeWithParent findNode) {
    return nodes.stream()
                .filter(node -> !Objects.equals(node.parent, findNode.parent))
                .map(node -> node.delegate.value)
                .collect(Collectors.toSet());
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
0

Implementation of the binary tree provided below allows to create a tree with exactly the same structure as in your example (take a look at the output).

This tree is balanced, and according to the provided tree schema it's not a BST. Hence the code below only accommodates balancing while adding nodes, so that that overall structure matches your example.

Code makes use of classic BFS and DFS algorithms.

    public class BinaryTree {
    private Node root;
    private Map<Integer, Node> idToNode;

    private BinaryTree(Node root) {
        this.root = root;
        this.idToNode = new HashMap<>();
    }

    public static BinaryTree getInstance(int rootId, int... elements) {
        BinaryTree tree = new BinaryTree(new Node(rootId));
        tree.addElements(elements);
        tree.discoverAllNodes();
        return tree;
    }

    public void addElements(int... elements) {
        IntStream.of(elements)
                .forEach(root::addElement);
    }

    public void discoverAllNodes() {
        Deque<Node> stack = new ArrayDeque<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            Node cur = stack.pop();
            idToNode.put(cur.getId(), cur);
            if (cur.getLeft() != null)
                stack.push(cur.getLeft());
            if (cur.getRight() != null)
                stack.push(cur.getRight());
        }
    }

    public List<Node> getCousins(int find) {
        Node target = new Node(find);
        if (target.equals(root)) return Collections.emptyList();
        
        int targetLevel = getNodeLevel(find);
        Queue<Node> curLevelNodes = new ArrayDeque<>();
        Queue<Node> nextLevelNodes = new ArrayDeque<>();
        curLevelNodes.add(root);
        for (int level = 0; level < targetLevel; level++) {
            while (!curLevelNodes.isEmpty()) {
                Node cur = curLevelNodes.remove();
                if (cur.getLeft() != null && !cur.getLeft().equals(target))
                    nextLevelNodes.add(cur.getLeft());
                if (cur.getRight() != null && !cur.getRight().equals(target))
                    nextLevelNodes.add(cur.getRight());
            }
            Queue<Node> emptyQueue = curLevelNodes; // reusing empty queue to avoid creating new collection
            curLevelNodes = nextLevelNodes;
            nextLevelNodes = emptyQueue;
        }

        return Collections.unmodifiableList(new ArrayList<>(curLevelNodes));
    }

    public int getNodeLevel(int find) {
        Node target = idToNode.get(find);
        if (target.equals(root)) return 0;

        boolean targetIsFound = false;
        int level = 0;
        Queue<Node> curLevelNodes = new ArrayDeque<>();
        Queue<Node> nextLevelNodes = new ArrayDeque<>();
        curLevelNodes.add(root);
        for (; !targetIsFound; level++) {
            while (!curLevelNodes.isEmpty()) {
                Node cur = curLevelNodes.remove();
                if (curNodePointToTargetNode(target, cur)) {
                    targetIsFound = true;
                    break;
                }
                if (cur.getLeft() != null && !cur.getLeft().equals(target))
                    nextLevelNodes.add(cur.getLeft());
                if (cur.getRight() != null && !cur.getRight().equals(target))
                    nextLevelNodes.add(cur.getRight());
            }
            if (targetIsFound) continue;

            Queue<Node> emptyQueue = curLevelNodes; // reusing empty queue to avoid creating new collection
            curLevelNodes = nextLevelNodes;
            nextLevelNodes = emptyQueue;
        }
        return level;
    }

    private boolean curNodePointToTargetNode(Node target, Node cur) {
        return cur.getLeft() != null && cur.getLeft().equals(target) ||
                cur.getRight() != null && cur.getRight().equals(target);
    }

    public Node getRoot() {
        return root;
    }

    public Map<Integer, Node> getIdToNode() {
        return Collections.unmodifiableMap(idToNode);
    }

    public static class Node {
        private final int id;
        private Node left;
        private Node right;

        public Node(int id) {
            this.id = id;
        }

        public void addElement(int nextId) {
            if (left == null) {
                left = new Node(nextId);
                return;
            }
            if (right == null) {
                right = new Node(nextId);
                return;
            }

            if (left.getMinHeight() <= right.getMinHeight()) {
                left.addElement(nextId);
            }
            else {
                right.addElement(nextId);
            }
        }

        private int getMinHeight() {
            if (left == null || right == null) return 0;

            int height = 0;
            boolean leafNodeFound = false;
            Queue<Node> curLevelNodes = new LinkedList<>();
            Queue<Node> nextLevelNodes = new LinkedList<>();
            curLevelNodes.add(this);
            for (; !leafNodeFound; height++) {
                while (!curLevelNodes.isEmpty()) {
                    Node cur = curLevelNodes.remove();
                    if (cur.getLeft() == null || cur.getRight() == null) {
                        leafNodeFound = true;
                        break;
                    }
                    nextLevelNodes.add(cur.getLeft());
                    nextLevelNodes.add(cur.getRight());
                }
                Queue<Node> emptyQueue = curLevelNodes; // reusing empty queue to avoid creating new collection
                curLevelNodes = nextLevelNodes;
                nextLevelNodes = emptyQueue;
            }
            return height;
        }

        public int getId() {
            return id;
        }

        public Node getLeft() {
            return left;
        }

        public Node getRight() {
            return right;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node node = (Node) o;
            return id == node.id;
        }

        @Override
        public int hashCode() {
            return Objects.hash(id);
        }

        @Override
        public String toString() {
            return "Node{" + id +'}';
        }
    }
}

main

   public static void main(String[] args) {
        BinaryTree tree = BinaryTree.getInstance(1, 2, 3, 4, 5, 6, 7);

        System.out.println("Root: " + tree.getRoot());
        System.out.println("All nodes: " + tree.getIdToNode());
        System.out.println("Node 2 - level: " + tree.getNodeLevel(2));
        System.out.println("Node 2 - cousins: " + tree.getCousins(2));
        System.out.println("Node 3 - level: " + tree.getNodeLevel(3));
        System.out.println("Node 3 - cousins: " + tree.getCousins(3));
        System.out.println("Node 4 - level: " + tree.getNodeLevel(4));
        System.out.println("Node 4 - cousins: " + tree.getCousins(4));
        System.out.println("Node 5 - level: " + tree.getNodeLevel(5));
        System.out.println("Node 5 - cousins: " + tree.getCousins(5));
        System.out.println("Node 6 - level: " + tree.getNodeLevel(6));
        System.out.println("Node 6 - cousins: " + tree.getCousins(6));
        System.out.println("Node 7 - level: " + tree.getNodeLevel(7));
        System.out.println("Node 7 - cousins: " + tree.getCousins(7));
    }

OUTPUT

Root: Node{1}
All nodes: {1=Node{1}, 2=Node{2}, 3=Node{3}, 4=Node{4}, 5=Node{5}, 6=Node{6}, 7=Node{7}}
Node 2 - level: 1
Node 2 - cousins: [Node{3}]
Node 3 - level: 1
Node 3 - cousins: [Node{2}]
Node 4 - level: 2
Node 4 - cousins: [Node{5}, Node{6}, Node{7}]
Node 5 - level: 2
Node 5 - cousins: [Node{4}, Node{6}, Node{7}]
Node 6 - level: 2
Node 6 - cousins: [Node{4}, Node{5}, Node{7}]
Node 7 - level: 2
Node 7 - cousins: [Node{4}, Node{5}, Node{6}]
Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46