-1

Lets say I have a n-ary tree something like below I need to find maximum value at each level and return like : [8,7,32] .

                        8
             4          3          7
         1   4 3    3  5 6 7    12 32 3 1

My Node will look something like below : public class Node {

public int val;
public List<Node> children;


public Node() {
    
}

public Node(int _val,List<Node> _children) {
    val=_val;
    children=_children;
}

I tried through recursion at each level get the elements and find the maximum but unable to do so.

sidkool3k
  • 43
  • 9
  • [Breath-first search / Level order traversal](https://en.wikipedia.org/wiki/Tree_traversal#Breadth-first_search_/_level_order) might help. --- A remark: method parameters are normally not prefixed with an underscore (`val = _val` -> `this.val = val`, `children = _children` -> `thislchildren = children`) – Turing85 Aug 20 '20 at 21:24

4 Answers4

1

We can get the level-maximum by a level order traversal / Breadth-first search. The idea is that we have a list/queue of nodes on one level. For all nodes in this list the algorithm does two things:

  1. It calculates the maximum value on this level.
  2. It iterates over all nodes of the list/queue, gets all children of those nodes and put them in a new list/queue, which it can then process in the next iteration.

The algorithm starts with a list/queue holding the root of the (sub)-tree and ends when the list/queue is empty.

This can be expressed nicely with Stream operations:

public static List<Integer> getMaxValuePerLevel(Node node) {
    final ArrayList<Integer> maxPerLevel = new ArrayList();
    maxPerLevel.add(node.getValue());
    List<Node> children = node.getChildren();
    while (!children.isEmpty()) {
        maxPerLevel.add(children.stream()
                .mapToInt(Node::getValue)
                .max()
                .getAsInt());
        children = children.stream()
                .map(Node::getChildren)
                .flatMap(List::stream)
                .collect(Collectors.toList());
    }
    return maxPerLevel;
}

Ideone demo

This implementation has two nice properties:

  • It is iterative, not recursive, i.e. the algorithm is not subject to a StackOverflowError
  • It has linear time- and memory complexity

With a little bit of effort, we are even able to make the algorithm work with generic Node<T extends Comparable<T>>:

public static <T extends Comparable<T>> List<T> getMaxValuePerLevel(Node<T> node) {
    final ArrayList<T> maxPerLevel = new ArrayList<>();
    maxPerLevel.add(node.getValue());
    List<Node<T>> children = node.getChildren();
    while (!children.isEmpty()) {
        final Node<T> defaultNode = children.get(0);
        maxPerLevel.add(children.stream()
                .map(Node::getValue)
                .max(Comparator.naturalOrder())
                .orElseGet(defaultNode::getValue));
        children = children.stream()
                .map(Node::getChildren)
                .flatMap(List::stream)
                .collect(Collectors.toList());
    }
    return maxPerLevel;
}

Ideone demo

Turing85
  • 13,364
  • 5
  • 27
  • 49
0

The root node is going to be the highest of its level. For the subsequent levels, call Collections.sort() (or any other comparison that will order your list) on the list of children nodes and take the last element (or whichever has the highest value according to the sorting method you used). Then iterate through the list of children nodes that you just sorted and for each node, apply the same treatment to its list of children.

JustAnotherDeveloper
  • 1,575
  • 2
  • 4
  • 18
0

A recursive solution is surprisingly simple. First create a list to hold the result. Then iterate through all the nodes: at each node you compare the node's value with the value in the list at the same level. If the node's value is greater, you replace the value in the list.

class Node {
    public int val;
    public List<Node> children;

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }

    public List<Integer> getMaxPerLevel() {
        List<Integer> levels = new ArrayList<>();
        getMaxPerLevel(0, levels);
        return levels;
    }

    private void getMaxPerLevel(int level, List<Integer> levels) {
        if (level >= levels.size()) {
            levels.add(level, val);
        } else {
            levels.set(level, Math.max(val, levels.get(level)));
        }
        for (Node child : children) {
            child.getMaxPerLevel(level + 1, levels);
        }
    }
}
Joni
  • 101,441
  • 12
  • 123
  • 178
0

Thanks everyone I did using below solution:

public List<Integer> levelOrder(Node node){
    List<Integer> result = new ArrayList<>();
    Queue<Node> queue = new LinkedList<Node>();
    queue.add(node);
    while(!queue.isEmpty()) {
        int size = queue.size();
        List<Integer> currentLevel = new ArrayList<Integer>();
        for(int i=0;i<size;i++) {
            Node current = queue.remove();
                currentLevel.add(current.val);
                for(Integer inte:currentLevel) {
                    System.out.println(inte);
                }
       
        if(current.children !=null) {
            for(Node node1:current.children)
            queue.add(node1);
        }
        }
      result.add(Collections.max(currentLevel));  
    }
return result;
}
sidkool3k
  • 43
  • 9