Day9-2021.1.17-剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。
2021年1月17日 时间都去哪了?
今日计划:
1.小学初中的辅导。任务已被安排~
2.组会
3.剑指offer的二叉树题目
4.图解tcp ip 的内容
今日工作:
1.小学初中的辅导。任务已被安排~
>2.组会
3.剑指offer的二叉树题目:剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。
>4.图解tcp ip 的内容
具体内容请点击这里,或者再往下拉一下,复制到下面了。
剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。
剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。
剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。
剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。
剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。
剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。
今日总结: 考虑一天多做几种类型的工作吧,别只刷题。
今日语录:
作者:paceMaK1.r
链接:https://www.zhihu.com/question/65532582/answer/1006046098 来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。朱砂痣美艳活泼,开放,一举一动都撩拨着你的心房,和她在一起有一种刺激的堕落感;白月光是年少时偷偷喜欢的三好学生,纯洁又内向,温柔又理性,你知道白月光是好姑娘,她永远都能在正确的道路上指引你。
和白月光在一起了,你们的生活渐渐平淡如水,她从曾经那个温柔又有学识,不食人间烟火的女孩变成了柴米油盐骂孩子起床的老妈子,你感到窒息,不由得想起年少时碰到的那一抹惊艳,再看看面前这个寡淡的女人,你后悔了。
她成了你胸口的一颗朱砂痣,在你的心头热烈而浓重,让你心跳加速,仿佛自己也年轻了不少。
选择了朱砂痣,那个漂亮外向的女人,她的容颜也会渐渐老去,年龄让她不可能再像一个小丫头一样和你打打闹闹。她变得聒噪,抱怨自己老去的容颜和你那不高的工资。
你们躺在床上,她已沉沉睡去,你还睡不着。你们曾经在这张床上翻云覆雨,哈哈大笑,现在的你却连搂着她睡觉都做不到。
你闭上双眼,感觉眼前一亮,睁开眼,窗外的月光温柔的抚摸着你的脸,你忽然想起学生时代那个红着脸给你讲题的女孩子,她博学多才,温柔可爱,比现在这个聒噪的女人好太多。
你凝视着月光的光束,她就像这个白月光一样,可望而不可即,是你心中永远的痛。
亦或者你根本选择不出来。年少时不管男女都会遇到这样两个完全不同的人,一个激情一个理智,一个爱闹一个平静。朱砂痣刺激你的荷尔蒙,白月光让你回归理智面对现实,但现实也并不是全都是理智组成。
但是,难道全世界的女子真的就只有安静和外向两个性格分别吗?
你从没注意过温婉的她偶尔也喜欢去唱歌喝酒,不小心说一两句脏话便突然害羞,开心起来也会双腿环绕着你的腰抱着你撒娇。
你也从没发现过大大咧咧的她居然喜欢研究宇宙,有时会因为思考活着的意义与人类的未来而惆怅,经常一个人看经典老片而哭的稀里哗啦。
在你的眼中没有完美,所有女人都被分为两类人,朱砂痣?白月光?
你要找的,从来不是一个你真心爱的人,而是一个既能让你充满激情又天真纯洁的人。那不是人,那是幻想。
真心爱一个人,不是朱砂痣也不是白月光,是这些名词之上的,深深爱着的人。
不要以为所有男人心中都有朱砂痣和白月光,他们只有相守一生的人,能分出朱砂痣和白月光的男人,做出什么选择都不是尽善尽美,喝醉后还会和朋友吹嘘年轻时没得到的那个女孩子和黄脸婆的你。
所以,亲爱的男孩啊,别再用这些名词将你对爱人的标准牢牢套住了,这些明明也并不尽善尽美的词汇,何必为自己的终生爱人冠以姓名?
她就是她,哪个也不是,她是你,最爱的人
完。
另一个评论:爱了一个又爱一个,渣的明目张胆,还取名白月光,朱砂痣,两个怕是你都不配拥有吧.
转到2021.1.9-2021.1.31的learning record 首页
明日计划:剑指offer的另外八道二叉树题目的整理。操作系统/计网面经?项目呢?啊…
2.二叉树
- 剑指 Offer 07 .重建二叉树
- 剑指 Offer 26 .树的子结构
- 剑指 Offer 27 .二叉树的镜像
- 剑指 Offer 28 .对称的二叉树
- 剑指 Offer 32 - I 从上到下打印二叉树
- 剑指 Offer 32 - II 从上到下打印二叉树 II
- 剑指 Offer 32 - III 从上到下打印二叉树 III
- 剑指 Offer 33 .二叉搜索树的后序遍历序列
- 剑指 Offer 34 .二叉树中和为某一值的路径
- 剑指 Offer 36 .二叉搜索树与双向链表
- 剑指 Offer 37 .序列化二叉树
- 剑指 Offer 54 .二叉搜索树的第k大节点
- 剑指 Offer 55 - I 二叉树的深度
- 剑指 Offer 55 - II 平衡二叉树
- 剑指 Offer 68 - I 二叉搜索树的最近公共祖先
- 剑指 Offer 68 - II 二叉树的最近公共祖先
一些功能函数
1.按照前序遍历去打印树。根→左→右
private static void printTree(TreeNode node) {System.out.printf("%d ", node.val);if (node.left != null) {printTree(node.left);}if (node.right != null) {printTree(node.right);}
}
2.对于Arrays.copyOfRange的测试用例。
import java.util.Arrays;public class Test {public static void main(String[] args) {// 对于Arrays.copyOfRange的测试用例int[] test = {0, 1, 2, 3, 4, 5, 6};int[] array = Arrays.copyOfRange(test, 1, 2);// 只存储了索引为1的元素。for (int a : array)//array的长度=1a=1System.out.println("array的长度=" + array.length + "a=" + a);}
}
1.剑指 Offer 07 .重建二叉树 【需要重刷】
思考:还是有点难度的。直接去看评论的讲解还是不容易理解的。推荐直接去看视频讲解:
通过遍历中序数组inorder,得到等于preorder[0](根节点)的索引index
,可以将中序遍历数组分开:
中序遍历数组=左子树的中序遍历数组Arrays.copyOfRange(inOrder, 0, index)
+根节点
+右子树的中序遍历数组Arrays.copyOfRange(inOrder, index + 1, inOrder.length - 1 + 1))
。
通过index
,以及中序遍历数组:左→根→右 的规律,那么左子树的长度为index-0=index。
那么前序遍历数组=根节点+左子树的前序遍历数组Arrays.copyOfRange(preOrder, 1, index + 1)
+右子树的前序遍历数组Arrays.copyOfRange(preOrder, index + 1, preOrder.length - 1 + 1)
。
import java.util.Arrays;public class Offer07 {public static void main(String[] args) {int[] preOrder = {1, 2, 4, 7, 3, 5, 6, 8}; /// 前序遍历int[] inOrder = {4, 7, 2, 1, 5, 3, 8, 6}; /// 中序遍历TreeNode root = buildTree(preOrder, inOrder);printTree(root);}public static TreeNode buildTree(int[] preOrder, int[] inOrder) {// Java中判断一维数组是否为空if (preOrder == null || preOrder.length == 0) {return null;}// preOrder 的第一个元素就是根节点。TreeNode root = new TreeNode(preOrder[0]);int index = findIndex(preOrder, inOrder);//root.left=buildTree(左子树的前序数组,左子树的中序数组)root.left = buildTree(Arrays.copyOfRange(preOrder, 1, index + 1), Arrays.copyOfRange(inOrder, 0, index));//root.right=buildTree(右子树的前序数组,右子树的中序数组)root.right = buildTree(Arrays.copyOfRange(preOrder, index + 1, preOrder.length - 1 + 1), Arrays.copyOfRange(inOrder, index + 1, inOrder.length - 1 + 1));return root;}public static int findIndex(int[] preOrder, int[] inOrder) {for (int i = 0; i < preOrder.length; i++) {if (inOrder[i] == preOrder[0]) {return i;}}return 0;}private static void printTree(TreeNode node) {System.out.printf("%d ", node.val);if (node.left != null) {printTree(node.left);}if (node.right != null) {printTree(node.right);}}
}
2.剑指 Offer 26 .树的子结构
思考:涉及到递归调用。如果你记住这个题目的做题的思想
,那么就容易做出来。具体的思想去看代码吧。
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
空树不是任意一个树的子结构,所以B不为空。非空树不可能是空树的子树,所以A不能为空。
判断B是不是A的子结构:AB完全相等、B是A的左子树的子结构、B是A的右子树的子结构、
AB完全相等:AB头结点值相等,左子树相等,右子树相等。
+子树相等=递归调用“AB完全相等”的业务代码
public class Offer26 {public static void main(String[] args) {TreeNode A = new TreeNode(1);A.left = new TreeNode(2);A.right = new TreeNode(3);printTree(A);System.out.println();TreeNode B = new TreeNode(1);B.left = null;B.right = new TreeNode(3);printTree(B);System.out.println();System.out.println(isSubStructure(A, B));}public static boolean isSubStructure(TreeNode A, TreeNode B) {// 输入条件限制// 空树不是任意一个树的子结构,所以B不为空。// 非空树不可能是空树的子树,所以A不能为空。if (A == null || B == null) {return false;}// 判断B是不是A的子结构:AB完全相等、B是A的左子树的子结构、B是A的右子树的子结构、return help(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);// ✖ 判断B是不是A的子结构:AB完全相等、A的左子树与B完全相等、A的右子树与B完全相等、// ✖ return help(A,B)||help(A.left,B)||help(A.right,B); }// 验证AB完全相等,那么AB头结点值相等,左子树相等,右子树相等。// 判断子树是否相等,需要递归调用"验证AB完全相等"的功能函数。private static boolean help(TreeNode A, TreeNode B) {// 递归终止条件 只要B为空,A不管为不为空,B都是A的子结构了,即 A中有出现和B相同的结构和节点值。if (B == null) {return true;}if (A == null && B != null) {return false;}// 业务代码// 验证AB完全相等,那么AB头结点值相等,左子树相等,右子树相等。return A.val == B.val && help(A.left, B.left) && help(A.right, B.right);}private static void printTree(TreeNode node) {System.out.printf("%d ", node.val);if (node.left != null) {printTree(node.left);}if (node.right != null) {printTree(node.right);}}
}
3.剑指 Offer 27 .二叉树的镜像
public class Offer27 {public static void main(String[] args) {TreeNode root = new TreeNode(4);root.left = new TreeNode(2);root.right = new TreeNode(7);root.left.left = new TreeNode(1);root.left.right = new TreeNode(3);root.right.left = new TreeNode(6);root.right.right = new TreeNode(9);printTree(root);System.out.println();printTree(mirrorTree(root));System.out.println();}// 二叉树的镜像,也就是左右子树互换。public static TreeNode mirrorTree(TreeNode root) {// 递归终止条件,if (root == null) {return null;}// 这个是c语言中swap交换A,B,两个数据值的模板。TreeNode temp = mirrorTree(root.left);root.left = mirrorTree(root.right);root.right = temp;return root;}private static void printTree(TreeNode root) {System.out.print(root.val);if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
4.剑指 Offer 28 .对称的二叉树
public class Offer28 {public static void main(String[] args) {TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(2);root.left.left = new TreeNode(3);root.left.right = new TreeNode(4);root.right.left = new TreeNode(4);root.right.right = new TreeNode(3);printTree(root);System.out.println();System.out.println(isSymmetric(root));}// 用来判断一棵二叉树是不是对称的public static boolean isSymmetric(TreeNode root) {// 空树肯定是镜像对称if (root == null) {return true;}// help,业务代码,用于判断左右子树是否对称return help(root.left, root.right);}public static boolean help(TreeNode left, TreeNode right) {//递归终止条件if (left == null && right == null) {return true;}// 上面已经去除了同时为空的情况,如果两者不同时为空,那么不可能镜像对称,则返回falseif (left == null || right == null) {return false;}// left.val==right.val && left.left=right.right && left.right=right.leftreturn left.val == right.val && help(left.left, right.right) && help(left.right, right.left);}private static void printTree(TreeNode root) {System.out.print(root.val);if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
5.剑指 Offer 32 - I 从上到下打印二叉树 【需要重刷】
ArrayList如何转换为int[]数组 https://blog.csdn.net/huanghanqian/article/details/73920439
这个是java8的特性
int[] res = list.stream().mapToInt(Integer::intValue).toArray();
思考:从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。这道题是:二叉树的宽度优先搜索
【需要重刷做法2+做法3。做法1是错误的。】
其实这题很明显就是二叉树的宽度优先搜索,
(1)递归调用的一种错误解法
下面贴出一个错误的解法,并思考这么做为什么错了。
这里用到的
递归调用的思想是,添加左右子树的值→递归调用左子树(添加左子树的左右子树的值)→递归调用右子树(添加右子树的左右子树的值)
前序遍历输出为:1->2->4->8->9->5->10->11->3->6->12->13->7->14->15
错误解法返回的答案为:[1, 2, 3, 4, 5, 8, 9, 10, 11, 6, 7, 12, 13, 14, 15]。45应该接67,但是没有接,是因为他没有遍历完一层的数据,就进入了下一层,然后再返回来的。
错误来源是:help(root.left, list); // 递归调用左子树(添加左子树的左右子树的值)
help(root.right, list);// 递归调用右子树(添加右子树的左右子树的值)
这样会先遍历完左子树,再去遍历右子树。修改目标,每次先去遍历完每一层的数据。
import java.util.ArrayList;// [0,2,4,1,null,3,-1,5,1,null,6,null,8]
public class Offer32_1_1 {public static void main(String[] args) {TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);root.left.right = new TreeNode(5);root.right.left = new TreeNode(6);root.right.right = new TreeNode(7);root.left.left.left = new TreeNode(8);root.left.left.right = new TreeNode(9);root.left.right.left = new TreeNode(10);root.left.right.right = new TreeNode(11);root.right.left.left = new TreeNode(12);root.right.left.right = new TreeNode(13);root.right.right.left = new TreeNode(14);root.right.right.right = new TreeNode(15);printTree(root);System.out.println();//System.out.println(levelOrder(root));//直观性的输出System.out.println(levelOrder2(root));}// 返回数组,那么可以先用链表去存数据,到最后再将链表转为数组// 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印public static int[] levelOrder(TreeNode root) {// 首先,判断输入是否为空if (root == null) {return new int[0];}ArrayList<Integer> list = new ArrayList<>();list.add(root.val);help(root, list);int[] res = list.stream().mapToInt(Integer::intValue).toArray();return res;}public static ArrayList<Integer> levelOrder2(TreeNode root) {// 首先,判断输入是否为空if (root == null) {return new ArrayList<>();}ArrayList<Integer> list = new ArrayList<>();list.add(root.val);help(root, list);return list;}// 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。// 做法类似于树的前序,中序,后序遍历,只不过之前是打印,现在是向链表里面添加元素// 递归调用的思想是,添加左右子树的值→递归调用左子树(添加左子树的左右子树的值)→递归调用右子树(添加右子树的左右子树的值)private static void help(TreeNode root, ArrayList<Integer> list) {System.out.println(list);// 这个是递归调用的终止条件if (root == null) {return;}// 节点为空,则自动跳过// 添加左右子树的值if (root.left != null) {list.add(root.left.val);}if (root.right != null) {list.add(root.right.val);}// 递归调用左子树(添加左子树的左右子树的值)help(root.left, list);// 递归调用右子树(添加右子树的左右子树的值)help(root.right, list);}private static void printTree(TreeNode root) {System.out.print(root.val+"->");if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
(2)递归调用【需要重刷】
思考:利用height,起到一个定位的作用。
下面代码的输出结果如下:
1->2->4->8->9->5->10->11->3->6->12->13->7->14->15->
height=0 list=[[]]
height=1 list=[[1], []]
height=2 list=[[1], [2], []]
height=3 list=[[1], [2], [4], []]
height=3 list=[[1], [2], [4], [8]]
height=2 list=[[1], [2], [4], [8, 9]]height=3 list=[[1], [2], [4, 5], [8, 9]]
height=3 list=[[1], [2], [4, 5], [8, 9, 10]]
height=1 list=[[1], [2], [4, 5], [8, 9, 10, 11]]
height=2 list=[[1], [2, 3], [4, 5], [8, 9, 10, 11]]height=3 list=[[1], [2, 3], [4, 5, 6], [8, 9, 10, 11]]
height=3 list=[[1], [2, 3], [4, 5, 6], [8, 9, 10, 11, 12]]
height=2 list=[[1], [2, 3], [4, 5, 6], [8, 9, 10, 11, 12, 13]]height=3 list=[[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13]]
height=3 list=[[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]][1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
import java.util.ArrayList;
import java.util.List;// [0,2,4,1,null,3,-1,5,1,null,6,null,8]
public class Offer32_1_2 {public static void main(String[] args) {TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);root.left.right = new TreeNode(5);root.right.left = new TreeNode(6);root.right.right = new TreeNode(7);root.left.left.left = new TreeNode(8);root.left.left.right = new TreeNode(9);root.left.right.left = new TreeNode(10);root.left.right.right = new TreeNode(11);root.right.left.left = new TreeNode(12);root.right.left.right = new TreeNode(13);root.right.right.left = new TreeNode(14);root.right.right.right = new TreeNode(15);printTree(root);System.out.println();// System.out.println(levelOrder(root));// 直观性的输出System.out.println(levelOrder2(root));}public static ArrayList<Integer> levelOrder2(TreeNode root) {ArrayList<ArrayList<Integer>> list = new ArrayList<>();levelHelper(list, root, 0);ArrayList<Integer> tempList = new ArrayList<>();for (int i = 0; i < list.size(); i++) {tempList.addAll(list.get(i));}return tempList;}// 返回数组,那么可以先用链表去存数据,到最后再将链表转为数组// 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印public static int[] levelOrder(TreeNode root) {ArrayList<ArrayList<Integer>> list = new ArrayList<>();levelHelper(list, root, 0);// 二维列表转为一维列表ArrayList<Integer> tempList = new ArrayList<>();for (int i = 0; i < list.size(); i++) {tempList.addAll(list.get(i));}//把list转化为数组
// int[] res = new int[tempList.size()];
// for (int i = 0; i < tempList.size(); i++) {// res[i] = tempList.get(i);
// }
// return res;int[] res = tempList.stream().mapToInt(Integer::intValue).toArray();return res;}// levelHelper 是主要的业务代码public static void levelHelper(ArrayList<ArrayList<Integer>> list, TreeNode root, int height) {// 判断输入节点是否为空if (root == null) {return;}// >= 中的等于,应该是做初始化的if (height >= list.size()) {list.add(new ArrayList<>());}// height起到了一个定位的作用System.out.println("height=" + height + " list=" + list);list.get(height).add(root.val);levelHelper(list, root.left, height + 1);levelHelper(list, root.right, height + 1);}private static void printTree(TreeNode root) {System.out.print(root.val + "->");if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
(3)二叉树的宽度优先搜索【需要重刷】
思考:二叉树的宽度优先搜索的题解:+建议先看视频讲解:
宽度优先搜索=层序遍历=利用队列queue去做。
思路:从队列queue中取出一个节点,并将其左右节点加入队列queue。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;// [0,2,4,1,null,3,-1,5,1,null,6,null,8]
public class Offer32_1_3 {public static void main(String[] args) {TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);root.left.right = new TreeNode(5);root.right.left = new TreeNode(6);root.right.right = new TreeNode(7);root.left.left.left = new TreeNode(8);root.left.left.right = new TreeNode(9);root.left.right.left = new TreeNode(10);root.left.right.right = new TreeNode(11);root.right.left.left = new TreeNode(12);root.right.left.right = new TreeNode(13);root.right.right.left = new TreeNode(14);root.right.right.right = new TreeNode(15);printTree(root);System.out.println();// System.out.println(levelOrder(root));// 直观性的输出System.out.println(levelOrder2(root));}// 返回数组,那么可以先用链表去存数据,到最后再将链表转为数组// 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印public static int[] levelOrder(TreeNode root) {if (root == null) {return new int[0];}Queue<TreeNode> queue = new LinkedList<>();queue.add(root);List<Integer> list = new ArrayList<>();while (!queue.isEmpty()) {TreeNode node = queue.poll();list.add(node.val);if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}int[] res = list.stream().mapToInt(Integer::intValue).toArray();return res;}public static List<Integer> levelOrder2(TreeNode root) {if (root == null) {return new ArrayList<>();}Queue<TreeNode> queue = new LinkedList<>();queue.add(root);List<Integer> list = new ArrayList<>();while (!queue.isEmpty()) {TreeNode node = queue.poll();list.add(node.val);if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}return list;}private static void printTree(TreeNode root) {System.out.print(root.val + "->");if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
6.剑指 Offer 32 - II 从上到下打印二叉树 II
(1)递归调用
思考:按照递归调用的方法。解法和32 - I 的解法(2)一模一样。
里面的一些小细节要非常注意哈
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;// [0,2,4,1,null,3,-1,5,1,null,6,null,8]
public class Offer32_2 {public static void main(String[] args) {TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);root.left.right = new TreeNode(5);root.right.left = new TreeNode(6);root.right.right = new TreeNode(7);root.left.left.left = new TreeNode(8);root.left.left.right = new TreeNode(9);root.left.right.left = new TreeNode(10);root.left.right.right = new TreeNode(11);root.right.left.left = new TreeNode(12);root.right.left.right = new TreeNode(13);root.right.right.left = new TreeNode(14);root.right.right.right = new TreeNode(15);printTree(root);System.out.println();System.out.println(levelOrder(root));}public static List<List<Integer>> levelOrder(TreeNode root) {if (root == null) {return new ArrayList<>();}List<List<Integer>> res = new ArrayList<>();help(root, res, 0);return res;}private static void help(TreeNode root, List<List<Integer>> res, int height) {if (root == null) {return;}if (height >= res.size()) {res.add(new ArrayList<>());}res.get(height).add(root.val);if (root.left != null) {help(root.left, res, height + 1);}if (root.right != null) {help(root.right, res, height + 1);}}private static void printTree(TreeNode root) {System.out.print(root.val + "->");if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
(2)广度优先搜索 从上到下打印二叉树 II 【需要重刷】
你多看几遍这道题,仔细考虑for里面为啥这么写。就能更加深刻的去理解广度优先遍历了。
这里和上面一道题目的区别是,上一题直接返回即可,这道题每一层就需要添加到一个链表里了。
实际输出一下,为什么会出错,将i++换成i--,两种程序的状态是?
+下面内容进行解释:
// 易错点:
// 这里的for如果写反了,如果写成i++,那就错了。
for (int i = queue.size(); i > 0; i--)
for (int i = 0; i < queue.size(); i++)
// 应该是这样说,在for循环中,queue.size()的大小随着queue不断的去添加元素,其大小是变化的,所以i < queue.size()的边界是动态的。
// 如果先去用 for (int i = queue.size(); i > 0; i--) ,那么i > 0的边界是确定的,所以不会输出错误的结果。// 更应该思考的是:queue 是存一层的元素,然后 poll 吐出来,存到链表 list 里面。
// 与此同时,去存储树的左右节点到队列 queue 中
// 由于队列的先入先出的特性,所以先去输出上一层的元素,再去输出下一层的元素。
// 正确的答案:
1->2->4->8->9->5->10->11->3->6->12->13->7->14->15->
i = 1 queue.size() = 2 temp = [1]i = 2 queue.size() = 3 temp = [2]
i = 1 queue.size() = 4 temp = [2, 3]i = 4 queue.size() = 5 temp = [4]
i = 3 queue.size() = 6 temp = [4, 5]
i = 2 queue.size() = 7 temp = [4, 5, 6]
i = 1 queue.size() = 8 temp = [4, 5, 6, 7]i = 8 queue.size() = 7 temp = [8]
i = 7 queue.size() = 6 temp = [8, 9]
i = 6 queue.size() = 5 temp = [8, 9, 10]
i = 5 queue.size() = 4 temp = [8, 9, 10, 11]
i = 4 queue.size() = 3 temp = [8, 9, 10, 11, 12]
i = 3 queue.size() = 2 temp = [8, 9, 10, 11, 12, 13]
i = 2 queue.size() = 1 temp = [8, 9, 10, 11, 12, 13, 14]
i = 1 queue.size() = 0 temp = [8, 9, 10, 11, 12, 13, 14, 15][[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14, 15]]
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;// [0,2,4,1,null,3,-1,5,1,null,6,null,8]
public class Offer32_2_2 {public static void main(String[] args) {TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);root.left.right = new TreeNode(5);root.right.left = new TreeNode(6);root.right.right = new TreeNode(7);root.left.left.left = new TreeNode(8);root.left.left.right = new TreeNode(9);root.left.right.left = new TreeNode(10);root.left.right.right = new TreeNode(11);root.right.left.left = new TreeNode(12);root.right.left.right = new TreeNode(13);root.right.right.left = new TreeNode(14);root.right.right.right = new TreeNode(15);printTree(root);System.out.println();System.out.println(levelOrder(root));}public static List<List<Integer>> levelOrder(TreeNode root) {Queue<TreeNode> queue = new LinkedList<>();List<List<Integer>> res = new ArrayList<>();if (root != null) {queue.add(root);}while (!queue.isEmpty()) {// 每次新建一个 list 去存储每一行的内容List<Integer> temp = new ArrayList<>();// 这里的for如果写反了,如果写成i++,那就错了。for (int i = queue.size(); i > 0; i--) {// for (int i = 0; i < queue.size(); i++) {TreeNode node = queue.poll();temp.add(node.val);if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}System.out.println("i = " + i + " queue.size() = " + queue.size() + " temp = " + temp);}System.out.println();res.add(temp);}return res;}private static void printTree(TreeNode root) {System.out.print(root.val + "->");if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
7.剑指 Offer 32 - III 从上到下打印二叉树 III
(1)递归调用
思考:递归调用,通过高度 height 来控制存储每一层的元素。
没想到合适的做法。明天再想吧。。。主要是这个三份“从上到下打印二叉树”做的脑袋都大了。迷。
(2)广度优先遍历
思考:相对于从上到下打印二叉树 II
的变化之处是在向每一层的链表中添加元素,按照奇偶性去选择向链表的首部添加元素,还是向链表的末尾添加元素。
这里借用了LinkedList 双向链表
+双向链表的功能。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;// [0,2,4,1,null,3,-1,5,1,null,6,null,8]
public class Offer32_3 {public static void main(String[] args) {TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);root.left.right = new TreeNode(5);root.right.left = new TreeNode(6);root.right.right = new TreeNode(7);root.left.left.left = new TreeNode(8);root.left.left.right = new TreeNode(9);root.left.right.left = new TreeNode(10);root.left.right.right = new TreeNode(11);root.right.left.left = new TreeNode(12);root.right.left.right = new TreeNode(13);root.right.right.left = new TreeNode(14);root.right.right.right = new TreeNode(15);printTree(root);System.out.println();System.out.println(levelOrder(root));}public static List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new ArrayList<>();Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {LinkedList<Integer> temp = new LinkedList<>();for (int i = queue.size(); i > 0; i--) {TreeNode node = queue.poll();if (res.size() % 2 == 0) {temp.addLast(node.val);} else {temp.addFirst(node.val);}if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}res.add(temp);}return res;}private static void printTree(TreeNode root) {System.out.print(root.val + "->");if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
8.剑指 Offer 33 .二叉搜索树的后序遍历序列 【需要重刷】
二叉搜索树,它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
您还没任何提交记录。哈哈。竟然没做过这个题目~
思考:单纯去看评论中的讲解是不容易理解的,点击这里去看视频讲解:
使用递归操作去求解问题。只是参考了视频中的解法。评论中大神们的做法还没有去深究。
import java.util.ArrayList;
import java.util.List;public class Offer33 {public static void main(String[] args) {// int[] postorder = new int[]{1, 6, 3, 2, 5};int[] postorder = new int[]{1, 3, 2, 6, 5};System.out.println(verifyPostorder(postorder));}public static boolean verifyPostorder(int[] postorder) {List<Integer> list = new ArrayList<>();// 二叉搜索树,它或者是一棵空树,或者是具有下列性质的二叉树if (postorder == null || postorder.length == 0) {// return false;return true;}// 为了便于操作。作者将数组转为链表for (int i = 0; i < postorder.length; i++) {list.add(postorder[i]);}return verifyBST(list);}// 递归操作public static boolean verifyBST(List<Integer> postorder) {if (postorder.size() < 1) {return true;}int len = postorder.size();// 后序遍历:左→右→根。根在数组/链表的末尾// get 是从 0 开始的。int rootVal = postorder.get(len - 1);List<Integer> leftList = new ArrayList<>();List<Integer> rightList = new ArrayList<>();int i = 0;// 为了便于操作。作者将数组转为链表。便利之处在这里,容易进行动态添加元素。// 左子树while (postorder.get(i) < rootVal) {// get(i++) 是先去获得get(i),然后i执行➕1的操作leftList.add(postorder.get(i++));}// 为了便于操作。作者将数组转为链表。便利之处在这里,容易进行动态添加元素。// 右子树while (postorder.get(i) > rootVal) {// get(i++) 是先去获得get(i),然后i执行➕1的操作rightList.add(postorder.get(i++));}if (i < postorder.size() - 1) {return false;}return verifyBST(leftList) && verifyBST(rightList);}private static void printTree(TreeNode root) {System.out.print(root.val);if (root.left != null) {printTree(root.left);}if (root.right != null) {printTree(root.right);}}
}
Day9-2021.1.17-剑指offer的八道二叉树题目的整理。涉及递归调用+广度优先遍历。相关推荐
- 剑指offer十八之二叉树的镜像
一.题目 操作给定的二叉树,将其变换为源二叉树的镜像.二叉树的镜像定义: 源二叉树 : 8/ \6 10/ \ / \5 7 9 11镜像二叉树:8/ \10 6/ \ / \11 9 7 5 二.思 ...
- 《LeetCode力扣练习》剑指 Offer 28. 对称的二叉树 Java
<LeetCode力扣练习>剑指 Offer 28. 对称的二叉树 Java 一.资源 题目: 请实现一个函数,用来判断一棵二叉树是不是对称的.如果一棵二叉树和它的镜像一样,那么它是对称的 ...
- DayDayUp之Job:牛客网—算法工程师—剑指offer之66道在线编程(解决思路及其代码)——1~20
DayDayUp之Job:牛客网-算法工程师-剑指offer之66道在线编程(解决思路及其代码)--01~20 目录 剑指offer--66道在线编程--01~20 1.二维数组中的查找某个targe ...
- DayDayUp之Job:牛客网—算法工程师—剑指offer之66道在线编程(解决思路及其代码)——41~66
DayDayUp之Job:牛客网-算法工程师-剑指offer之66道在线编程(解决思路及其代码)--41~66 目录 剑指offer之66道在线编程--41~66 42.和为s的两个数字 43.左旋转 ...
- DayDayUp之Job:牛客网—算法工程师—剑指offer之66道在线编程(解决思路及其代码)——21~40
DayDayUp之Job:牛客网-算法工程师-剑指offer之66道在线编程(解决思路及其代码)--21~41 目录 剑指offer之66道在线编程--21~41 21.栈的压入.弹出序列 22.从上 ...
- LeetCode Algorithm 剑指 Offer 28. 对称的二叉树
剑指 Offer 28. 对称的二叉树 Ideas 一开始想的有问题,看了例子以为对称二叉树的中序遍历序列是回文数组,然后就用这么写了,结果到第192个测试用例[1,2,2,2,null,2]就失败了 ...
- 【LeetCode】剑指 Offer 28. 对称的二叉树
[LeetCode]剑指 Offer 28. 对称的二叉树 文章目录 [LeetCode]剑指 Offer 28. 对称的二叉树 一.递归 一.递归 对称二叉树定义:对于书中任意两个对称结点 L 和 ...
- 剑指offer——复习1:二叉树三种遍历方式的迭代与递归实现
剑指offer--复习1:二叉树三种遍历方式的迭代与递归实现 20180905更新:这个博客中的解法不是很好,看相应的LeetCode题目笔记~~~ 我感觉此博客中的说法更容易让人理解:https:/ ...
- 最新算法校招编程-剑指offer、Leetcode常考题目及解法分享
本资源整理了BAT.TMD等互联网算法岗校招面试过程中常考的LeetCode和剑指offer编程题:此外,还整理了部分百度.腾讯.阿里.今日头条相关的面试经验,对于正准备校招面试的同学非常值得参考复习 ...
最新文章
- python学习--基础
- java springcloud版b2b2c社交电商spring cloud分布式微服务(十三)断路器聚合监控(Hystrix Turbine)...
- 计算机网络的组成相关,计算机网络的组成
- linux内核加载卡主,请教mx6,linux3.0.35,tf卡能启动uboot但是无法加载内核问题
- 路痴的单身小菡 BFS求最短路径+DFS求路径数
- 优雅地在Mac+Valet环境下本地部署phphub
- linux运维和3dmax哪个简单,牛逼运维常用的工具系列-2
- java基础—多线程下的单例设计模式的安全问题
- Vue生命周期通俗理解
- (转)Uncaught TypeError: Cannot set property 'innerHTML' of null
- [包计划] create-react-app
- Codeforces.741D.Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree 思路)
- 网络系统设计的一般步骤
- 手机定位折腾记(1):安卓手机的网络定位与NetworkLocation.apk
- jvm的内存回收机制
- matlab 实现马赫带效应,图像上机实验.doc
- android如何增加北斗定位,安卓手机怎么设置北斗导航图文教程
- 那些拿到腾讯、阿里等大厂offer的人,都有这个共同点
- 毕业设计/论文答辩演讲稿通用模板
- android 仿微信来电_仿MIUI、微信来电通知无法解决通知折叠到通知列表
热门文章
- servlet的url-pattern匹配规则
- java jackson2.6_Jackson 2 - Convert Java Object to JSON and JSON String to Object
- 【多目标跟踪任务——评价指标】
- MOOC 数据结构 | 4. 树(中)
- 编写程序,将一年中 12 个月,建立一个枚举类型数据,并对其进行调用
- miui12超级壁纸怎么设置?
- Ubuntu18.04 小米游戏本最早一代 双硬盘 安装 过程记录
- Pytorch有关学习率的使用总结
- 蛤蜊丝瓜汤怎么做 蛤蜊丝瓜汤的做法
- 韩顺平 数据结构与算法 (12_3) 树结构应用部分_赫夫曼编码(思路)