数据结构在N叉树的每一层获取最大值

huangapple go评论83阅读模式
英文:

Data structures get maximum value at each level of N-ary tree

问题

假设我有一个类似下面的 n 叉树,我需要找到每一层的最大值并返回,结果应该是 [8, 7, 32]

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

我的节点类大致如下:

public class Node {

	public int val;
	public List<Node> children;

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

我尝试了通过递归,在每一层获取元素并找到最大值,但是无法成功。

英文:

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&lt;Node&gt; children;


public Node() {
	
}

public Node(int _val,List&lt;Node&gt; _children) {
	val=_val;
	children=_children;
}

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

答案1

得分: 1

我们可以通过层序遍历 / 广度优先搜索来获得每一层的最大值。算法的思想是,我们有一个存储某一层节点的列表/队列。对于该列表中的所有节点,算法执行两件事情:

  1. 计算该层上的最大值。
  2. 遍历列表/队列中的所有节点,获取这些节点的所有子节点,并将它们放入一个新的列表/队列中,在下一次迭代中可以进行处理。

算法从持有(子)树的根开始,并在列表/队列为空时结束。

这可以通过 Stream 操作来很好地表达:

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;
}

<kbd>Ideone 演示</kbd>

此实现具有两个优点:

  • 它是迭代的,而不是递归的,即算法不会出现 StackOverflowError
  • 它具有线性的时间和内存复杂度

稍微努力一下,我们甚至可以使该算法适用于泛型 Node&lt;T extends Comparable&lt;T&gt;&gt;

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;
}

<kbd>Ideone 演示</kbd>

英文:

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&lt;Integer&gt; getMaxValuePerLevel(Node node) {
    final ArrayList&lt;Integer&gt; maxPerLevel = new ArrayList();
    maxPerLevel.add(node.getValue());
    List&lt;Node&gt; 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;
}

<kbd>Ideone demo</kbd>

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&lt;T extends Comparable&lt;T&gt;&gt;:

public static &lt;T extends Comparable&lt;T&gt;&gt; List&lt;T&gt; getMaxValuePerLevel(Node&lt;T&gt; node) {
    final ArrayList&lt;T&gt; maxPerLevel = new ArrayList&lt;&gt;();
    maxPerLevel.add(node.getValue());
    List&lt;Node&lt;T&gt;&gt; children = node.getChildren();
    while (!children.isEmpty()) {
        final Node&lt;T&gt; 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;
}

<kbd>Ideone demo</kbd>

答案2

得分: 0

根节点将是其所在层级中的最高节点。对于后续层级,在子节点列表上调用 Collections.sort()(或任何其他能对列表进行排序的比较方法),选择最后一个元素(或根据所使用的排序方法具有最高值的元素)。然后迭代刚刚排序过的子节点列表,并对每个节点将相同的处理应用于其子节点列表。

英文:

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.

答案3

得分: 0

一个递归的解决方案出奇地简单。首先创建一个列表来保存结果。然后遍历所有的节点:在每个节点,将节点的值与同一层级列表中的值进行比较。如果节点的值较大,则替换列表中的值。

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);
        }
    }
}
英文:

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&lt;Node&gt; children;

    public Node(int _val, List&lt;Node&gt; _children) {
        val = _val;
        children = _children;
    }

    public List&lt;Integer&gt; getMaxPerLevel() {
        List&lt;Integer&gt; levels = new ArrayList&lt;&gt;();
        getMaxPerLevel(0, levels);
        return levels;
    }

    private void getMaxPerLevel(int level, List&lt;Integer&gt; levels) {
        if (level &gt;= 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);
        }
    }
}

答案4

得分: 0

感谢大家,我使用了以下解决方案:

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;
}
英文:

Thanks everyone I did using below solution:

public List&lt;Integer&gt; levelOrder(Node node){
	List&lt;Integer&gt; result = new ArrayList&lt;&gt;();
	Queue&lt;Node&gt; queue = new LinkedList&lt;Node&gt;();
	queue.add(node);
	while(!queue.isEmpty()) {
		int size = queue.size();
		List&lt;Integer&gt; currentLevel = new ArrayList&lt;Integer&gt;();
	    for(int i=0;i&lt;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;
}

huangapple
  • 本文由 发表于 2020年8月21日 05:22:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/63513292.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定