【问题标题】:Checking to see if cousins of a given node and adding to an arrayList检查给定节点的表兄弟是否并添加到 arrayList
【发布时间】:2022-01-23 17:53:49
【问题描述】:

如何使用 BFS 或 DFS 获取给定节点的所有表兄弟并添加到 ArrayList。如果有人能帮忙指出我的逻辑哪里错了

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;

}

【问题讨论】:

  • 先调用哪个方法?如果您不介意,您可以与示例 I/O 分享确切的问题陈述吗?
  • 我正在将 findLevel 与 printCousins 方法中的兄弟姐妹进行比较。如果你所说的“你能分享确切的问题陈述......”,我还附上了确切的问题。 @nice_dev
  • 是的,这很有意义。问题似乎完成了。
  • 能否请您花几分钟时间评估答案并接受最好的答案。这不是最简单的问题,帮我们一个忙
  • 我肯定会@AlexanderIvanchenko

标签: java algorithm data-structures depth-first-search breadth-first-search


【解决方案1】:

我可以看到这个任务很简单BFS - Breadth-first search。您所需要的只是找到一个级别,其中您的目标节点并打印具有不同父节点的同一级别的所有其他节点,如果您保留每个节点的父节点,这可能会非常容易(我提供使用附加类 @987654322 来做到这一点@)。

// 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());
}

【讨论】:

    【解决方案2】:

    下面提供的二叉树的实现允许创建与您的示例中完全相同的结构的树(查看输出)。

    这棵树是平衡的,根据提供的树模式,它不是 BST。因此,下面的代码仅在添加节点时适应平衡,以便整体结构与您的示例相匹配。

    代码使用经典的 BFS 和 DFS 算法。

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

    主要

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

    输出

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

    【讨论】:

      【解决方案3】:

      在您的方法中,您似乎假设堂兄弟只能有 1 个不同的父母。我们越深入,特定find 节点的不同 父节点就越多,或者您可以说表亲越多。此外,if(root.left == find &amp;&amp; root.right == find){ 没有意义,因为树中不能有 2 个相同的节点,尤其是 find


      在您的printCousins 中,您需要找到find 节点的级别,然后通过将其传递给siblings 方法来收集它的所有表亲。

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

      由于您使用深度优先搜索技术,您可以先找到find 节点的级别,如下所示:

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

      siblings 中,您将把所有位于level 的节点添加到arr,并仔细检查父级没有find 作为他们的孩子之一,从而确保不同的父级具有相同级别的要求。

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

      【讨论】:

      • 我用缺失的部分更新了我的答案。
      • 对于 findLevel 方法,级别已在范围内定义,因此您需要编辑代码@nice_dev
      • @SEJU 抱歉打错了。现已修复。
      • @SEJU 成功了吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-18
      相关资源
      最近更新 更多