用任意合法序列建立一棵二叉树(洛谷P1305题题解,Java语言描述)

前言

这题是极其麻烦极其麻烦的一道题(前提是你不知道它有套路)……
我们不讲那些歪门邪道,我们正儿八经的解一下,想正经求解,很麻烦很麻烦。。。

题目要求

P1305题题解

在这里插入图片描述

分析

这题你看着容易,那是你想当然认为建立一棵树,给你的序列就是先根的,其实真实情况里不一定是……(当然本题是,所以是橙题……)

这题肝的我简直要暴毙,要多麻烦有多麻烦,大家如果有改进策略请告诉我,我会虚心接受了。。。写这么长代码累死人啦!!

我讲讲我分析的思路吧:

我们要自己编写结点类,其实结点凑起来就是tree,我们控一下root就可以咯。
手写Node,由于指定类型,所以不加泛型,不加setter、getter,玩最简单的版本:

    static class Node {
        char data;
        Node left, right;
        Node(char data) {
            this.data = data;
            this.left = null;
            this.right = null;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node node = (Node) o;
            return data == node.data;
        }
        @Override
        public int hashCode() {
            return Objects.hash(data);
        }
    }

对咯,这个必须是(静态)内部类,因为luoguOJ不识别,你写成另一个class会判CE的。。。。。。静态的内部类是OK的,因为静态不能访问非静态的,这会给方法里的调用带来麻烦。
还有就是一定要重写hashCode()和equals(),我们可是需要用data来区别Node的呀!!

首先我们建立一棵树,需要建立临时根结点,由于我们想知道这个结点是否已经在树里面,我们不想再次遍历,那我们可以建立一个HashMap,存储已经加入树中的结点
我们还需要一个HashMap,用来为未插入树中的结点提供查找的便利

将初始化的根结点保存为根结点,左右儿子加上去。不过这个题无论何时都要注意 ‘*’ 的存在,必须不能插入data为 ‘*’ 的结点。

接下来开循环,每次读一行数据,然后切成三份(toCharArray()),用三个char存储。
循环里面先看看这个临时的根结点是不是在map里,如果有就说明它在树里,它不可能还有左右儿子,所以肯定是原先作为某个子结点的,进行一下替换。
如果不在map里,就去unAddedMap里找,这里有的话思路同上,只不过这是一群没加入树里的临时树,相当于与真正的树构成了一个森林而已……
如果都不在,那好,这就是没有出现过的结点,我们看看它是不是新的根结点,这个判断要用临时根结点的左右儿子分别与当前真实根节点比较,如果equals就换根,注意换根以后要查右儿子在不在unAddedMap里(肯定不在map里)。。如果不是换根的情况那就只能把它塞进unAddedMap里了,毕竟这在当前是一棵 “孤儿树”,无依无靠呜呜呜~~

大致是这样,具体的看我代码注释吧,能看完说明你是个狠人,哦不,狼人(比狠人还狠一、)。。。

哦哦哦,差点忘说了,这个算法有一部分的逻辑是这样的:
毕竟我们这个森林是需要合并的,当合并的时候呢,就要把unAddedMap里的那个结点换掉临时结点(未来的老祖宗——新根)的某个儿子(我WA的那次就是因为这个原因,太难了),然后在unAddedMap里递归删除,在map里递归插入。。。。

这需要两个static的辅助方法(private即可),很nice!!!

递归删除

    private static void deleteRecursively(Node root, Map<Character, Node> unAddedMap) {
        if (root == null) {
            return;
        }
        unAddedMap.remove(root.data);
        deleteRecursively(root.left, unAddedMap);
        deleteRecursively(root.right, unAddedMap);
    }

递归插入

    private static void addRecursively(Node root, Map<Character, Node> map) {
        if (root == null) {
            return;
        }
        map.put(root.data, root);
        addRecursively(root.left, map);
        addRecursively(root.right, map);
    }

最后的结果也需要递归先序遍历

    private static void preOrder(Node root) {
        if (root == null) {
            return;
        }
        System.out.print(root.data);
        preOrder(root.left);
        preOrder(root.right);
    }

第一次提交——CE

这次CE就是因为没把Node类作为内部类,不能被OJ识别所以判错。。。。

第二次提交——WA

这个WA就是因为没换,具体原因我忘了诶,代码奉上,可以自己发掘其“魅力”(毫无魅力的破代码)
这是错的哈,正解在下面。。。

import java.util.*;

public class Main {

    static class Node {
        char data;
        Node left, right;
        Node(char data) {
            this.data = data;
            this.left = null;
            this.right = null;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node node = (Node) o;
            return data == node.data;
        }
        @Override
        public int hashCode() {
            return Objects.hash(data);
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int num = Integer.parseInt(scanner.nextLine());
        if (num == 0) {
            return;
        }
        //树非空,进行一系列初始化
        Map<Character, Node> map = new HashMap<>(num);
        Map<Character, Node> unAddedMap = new HashMap<>(num);
        char[] firstChars = scanner.nextLine().toCharArray();
        //初始化根结点
        Node root = new Node(firstChars[0]);
        map.put(firstChars[0], root);
        if (firstChars[1] != '*') {
            root.left = new Node(firstChars[1]);
            map.put(firstChars[1], root.left);
        }
        if (firstChars[2] != '*') {
            root.right = new Node(firstChars[2]);
            map.put(firstChars[2], root.right);
        }
        //循环num-1次
        for (int i = 1; i < num; i++) {
            char[] chars = scanner.nextLine().toCharArray();
            //根、左儿子、右儿子的char
            char tempRootChar = chars[0], tempLeftChar = chars[1], tempRightChar = chars[2];
            //临时的根结点、左儿子结点、右儿子结点
            Node tempRoot, tempLeft, tempRight;
            //Map里已有,也就是说已经存在临时父结点,而且子结点也有咯
            if (map.containsKey(tempRootChar)) {
                tempRoot = map.get(tempRootChar);
                //子结点必定不存在于Map,但要看看unAdded
                if (unAddedMap.containsKey(tempLeftChar)) {
                    tempLeft = unAddedMap.get(tempLeftChar);
                    root.left = tempLeft;
                    addRecursively(tempLeft, map);
                    deleteRecursively(tempLeft, unAddedMap);
                } else if (tempLeftChar == '*') {
                    tempLeft = null;
                } else {
                    tempLeft = new Node(tempLeftChar);
                }
                if (unAddedMap.containsKey(tempRightChar)) {
                    tempRight = unAddedMap.get(tempRightChar);
                    root.right = tempRight;
                    addRecursively(tempRight, map);
                    deleteRecursively(tempRight, unAddedMap);
                } else if (tempRightChar == '*') {
                    tempRight = null;
                } else {
                    tempRight = new Node(tempRightChar);
                }
                //插入左右儿子节点
                tempRoot.left = tempLeft;
                tempRoot.right = tempRight;
            } else if (unAddedMap.containsKey(tempRootChar)) {  //这就是说它的父结点已经存在咯,然后还没插进树里
                //继续放在unAdded里
                tempRoot = unAddedMap.get(tempRootChar);
                //子结点必定不存在
                //插入左右儿子节点
                if (tempLeftChar != '*') {
                    tempLeft = new Node(tempLeftChar);
                    tempRoot.left = tempLeft;
                    unAddedMap.put(tempLeftChar, tempLeft);
                }
                if (tempRightChar != '*') {
                    tempRight = new Node(tempRightChar);
                    tempRoot.right = tempRight;
                    unAddedMap.put(tempRightChar, tempRight);
                }
            } else {        //两边都没有,看看是不是子结点就是现在的根
                tempRoot = new Node(tempRootChar);
                if (tempLeftChar == '*') {
                    tempLeft = null;
                } else {
                    tempLeft = new Node(tempLeftChar);
                    tempRoot.left = tempLeft;
                }
                if (tempRightChar == '*') {
                    tempRight = null;
                } else {
                    tempRight = new Node(tempRightChar);
                    tempRoot.right = tempRight;
                }
                if (root.equals(tempLeft)) {        //左儿子是根结点,换根
                    tempLeft = root;
                    tempRoot.left = tempLeft;
                    root = tempRoot;
                    //查找右儿子
                    if (unAddedMap.containsKey(tempRightChar)) {
                        tempRight = unAddedMap.get(tempRightChar);
                        root.right = tempRight;
                        addRecursively(tempRight, map);
                        deleteRecursively(tempRight, unAddedMap);
                    }
                } else if (root.equals(tempRight)) {        //右儿子是根结点,换根
                    tempRight = root;
                    tempRoot.right = tempRight;
                    root = tempRoot;
                    //查找左儿子
                    if (unAddedMap.containsKey(tempLeftChar)) {
                        tempLeft = unAddedMap.get(tempLeftChar);
                        root.left = tempLeft;
                        addRecursively(tempLeft, map);
                        deleteRecursively(tempLeft, unAddedMap);
                    }
                } else {                        //插入unAdded里
                    if (unAddedMap.containsKey(tempLeftChar)) {
                        tempRoot.left = unAddedMap.get(tempLeftChar);
                    } else if (tempLeftChar != '*') {
                        unAddedMap.put(tempLeftChar, tempLeft);
                    }
                    if (unAddedMap.containsKey(tempRightChar)) {
                        tempRoot.right = unAddedMap.get(tempRightChar);
                    } else if (tempRightChar != '*') {
                        unAddedMap.put(tempRightChar, tempRight);
                    }
                    unAddedMap.put(tempRootChar, tempRoot);
                }
            }
        }
        scanner.close();
        preOrder(root);
    }

    private static void preOrder(Node root) {
        if (root == null) {
            return;
        }
        System.out.print(root.data);
        preOrder(root.left);
        preOrder(root.right);
    }

    private static void deleteRecursively(Node root, Map<Character, Node> unAddedMap) {
        if (root == null) {
            return;
        }
        unAddedMap.remove(root.data);
        deleteRecursively(root.left, unAddedMap);
        deleteRecursively(root.right, unAddedMap);
    }

    private static void addRecursively(Node root, Map<Character, Node> map) {
        if (root == null) {
            return;
        }
        map.put(root.data, root);
        addRecursively(root.left, map);
        addRecursively(root.right, map);
    }

}

在这里插入图片描述

哦~~我竟截图为证。。。
好吧,改的是这里,就AC了:
在这里插入图片描述
在这里插入图片描述

AC代码(Java语言描述)

import java.util.*;

public class Main {

    static class Node {
        char data;
        Node left, right;
        Node(char data) {
            this.data = data;
            this.left = null;
            this.right = null;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node node = (Node) o;
            return data == node.data;
        }
        @Override
        public int hashCode() {
            return Objects.hash(data);
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int num = Integer.parseInt(scanner.nextLine());
        if (num == 0) {
            return;
        }
        //树非空,进行一系列初始化
        Map<Character, Node> map = new HashMap<>(num);
        Map<Character, Node> unAddedMap = new HashMap<>(num);
        char[] firstChars = scanner.nextLine().toCharArray();
        //初始化根结点
        Node root = new Node(firstChars[0]);
        map.put(firstChars[0], root);
        if (firstChars[1] != '*') {
            root.left = new Node(firstChars[1]);
            map.put(firstChars[1], root.left);
        }
        if (firstChars[2] != '*') {
            root.right = new Node(firstChars[2]);
            map.put(firstChars[2], root.right);
        }
        //循环num-1次
        for (int i = 1; i < num; i++) {
            char[] chars = scanner.nextLine().toCharArray();
            //根、左儿子、右儿子的char
            char tempRootChar = chars[0], tempLeftChar = chars[1], tempRightChar = chars[2];
            //临时的根结点、左儿子结点、右儿子结点
            Node tempRoot, tempLeft, tempRight;
            //Map里已有,也就是说已经存在临时父结点,而且子结点肯定没有
            if (map.containsKey(tempRootChar)) {
                tempRoot = map.get(tempRootChar);
                //子结点必定不存在于Map,但要看看unAdded
                if (unAddedMap.containsKey(tempLeftChar)) {
                    tempLeft = unAddedMap.get(tempLeftChar);
                    root.left = tempLeft;
                    addRecursively(tempLeft, map);
                    deleteRecursively(tempLeft, unAddedMap);
                } else if (tempLeftChar == '*') {
                    tempLeft = null;
                } else {
                    tempLeft = new Node(tempLeftChar);
                    map.put(tempLeftChar, tempLeft);
                }
                if (unAddedMap.containsKey(tempRightChar)) {
                    tempRight = unAddedMap.get(tempRightChar);
                    root.right = tempRight;
                    addRecursively(tempRight, map);
                    deleteRecursively(tempRight, unAddedMap);
                } else if (tempRightChar == '*') {
                    tempRight = null;
                } else {
                    tempRight = new Node(tempRightChar);
                    map.put(tempRightChar, tempRight);
                }
                //插入左右儿子节点
                tempRoot.left = tempLeft;
                tempRoot.right = tempRight;
            } else if (unAddedMap.containsKey(tempRootChar)) {  //这就是说它的父结点已经存在咯,然后还没插进树里
                //继续放在unAdded里
                tempRoot = unAddedMap.get(tempRootChar);
                //子结点必定不存在
                //插入左右儿子节点
                if (tempLeftChar != '*') {
                    tempLeft = new Node(tempLeftChar);
                    tempRoot.left = tempLeft;
                    unAddedMap.put(tempLeftChar, tempLeft);
                }
                if (tempRightChar != '*') {
                    tempRight = new Node(tempRightChar);
                    tempRoot.right = tempRight;
                    unAddedMap.put(tempRightChar, tempRight);
                }
            } else {        //两边都没有,看看是不是子结点就是现在的根
                tempRoot = new Node(tempRootChar);
                if (tempLeftChar == '*') {
                    tempLeft = null;
                } else {
                    tempLeft = new Node(tempLeftChar);
                    tempRoot.left = tempLeft;
                }
                if (tempRightChar == '*') {
                    tempRight = null;
                } else {
                    tempRight = new Node(tempRightChar);
                    tempRoot.right = tempRight;
                }
                if (root.equals(tempLeft)) {        //左儿子是根结点,换根
                    tempLeft = root;
                    tempRoot.left = tempLeft;
                    root = tempRoot;
                    //查找右儿子
                    if (unAddedMap.containsKey(tempRightChar)) {
                        tempRight = unAddedMap.get(tempRightChar);
                        root.right = tempRight;
                        addRecursively(tempRight, map);
                        deleteRecursively(tempRight, unAddedMap);
                    }
                } else if (root.equals(tempRight)) {        //右儿子是根结点,换根
                    tempRight = root;
                    tempRoot.right = tempRight;
                    root = tempRoot;
                    //查找左儿子
                    if (unAddedMap.containsKey(tempLeftChar)) {
                        tempLeft = unAddedMap.get(tempLeftChar);
                        root.left = tempLeft;
                        addRecursively(tempLeft, map);
                        deleteRecursively(tempLeft, unAddedMap);
                    }
                } else {                        //插入unAdded里
                    if (unAddedMap.containsKey(tempLeftChar)) {
                        tempRoot.left = unAddedMap.get(tempLeftChar);
                    } else if (tempLeftChar != '*') {
                        unAddedMap.put(tempLeftChar, tempLeft);
                    }
                    if (unAddedMap.containsKey(tempRightChar)) {
                        tempRoot.right = unAddedMap.get(tempRightChar);
                    } else if (tempRightChar != '*') {
                        unAddedMap.put(tempRightChar, tempRight);
                    }
                    unAddedMap.put(tempRootChar, tempRoot);
                }
            }
        }
        scanner.close();
        preOrder(root);
    }

    private static void preOrder(Node root) {
        if (root == null) {
            return;
        }
        System.out.print(root.data);
        preOrder(root.left);
        preOrder(root.right);
    }

    private static void deleteRecursively(Node root, Map<Character, Node> unAddedMap) {
        if (root == null) {
            return;
        }
        unAddedMap.remove(root.data);
        deleteRecursively(root.left, unAddedMap);
        deleteRecursively(root.right, unAddedMap);
    }

    private static void addRecursively(Node root, Map<Character, Node> map) {
        if (root == null) {
            return;
        }
        map.put(root.data, root);
        addRecursively(root.left, map);
        addRecursively(root.right, map);
    }

}

在这里插入图片描述

感想

这代码真简(la)洁(ji)。。。
我迷了,不过自己手写一次满有收获的诶,奥利给!!!!
容我休息一下~~~
写代码好快(tou)乐(tu)。。。。
您能看完,是赏脸的,菜鸡拜谢Orz
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

传说七只Orz的自己可以召唤神龙哇!!!

发布了351 篇原创文章 · 获赞 610 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43896318/article/details/103737815