用任意合法序列建立一棵二叉树(洛谷P1305题题解,Java语言描述)
前言
這題是極其麻煩極其麻煩的一道題(前提是你不知道它有套路)……
我們不講那些歪門邪道,我們正兒八經的解一下,想正經求解,很麻煩很麻煩。。。
題目要求
P1305題題解
分析
這題你看著容易,那是你想當然認為建立一棵樹,給你的序列就是先根的,其實真實情況里不一定是……(當然本題是,所以是橙題……)
這題肝的我簡直要暴斃,要多麻煩有多麻煩,大家如果有改進策略請告訴我,我會虛心接受了。。。寫這么長代碼累死人啦!!
我講講我分析的思路吧:
我們要自己編寫結點類,其實結點湊起來就是tree,我們控一下root就可以咯。
手寫Node,由于指定類型,所以不加泛型,不加setter、getter,玩最簡單的版本:
對咯,這個必須是(靜態)內部類,因為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就是因為沒換,具體原因我忘了誒,代碼奉上,可以自己發掘其“魅力”(毫無魅力的破代碼)
這是錯的哈,正解在下面。。。
哦~~我竟截圖為證。。。
好吧,改的是這里,就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;}@Overridepublic 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;}@Overridepublic 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();//根、左兒子、右兒子的charchar tempRootChar = chars[0], tempLeftChar = chars[1], tempRightChar = chars[2];//臨時的根結點、左兒子結點、右兒子結點Node tempRoot, tempLeft, tempRight;//Map里已有,也就是說已經存在臨時父結點,而且子結點肯定沒有if (map.containsKey(tempRootChar)) {tempRoot = map.get(tempRootChar);//子結點必定不存在于Map,但要看看unAddedif (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的自己可以召喚神龍哇!!!
總結
以上是生活随笔為你收集整理的用任意合法序列建立一棵二叉树(洛谷P1305题题解,Java语言描述)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python】Matplotlib绘制
- 下一篇: 【CSS3】CSS3文本字体相关属性大全