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.二叉树

  1. 剑指 Offer 07 .重建二叉树
  2. 剑指 Offer 26 .树的子结构
  3. 剑指 Offer 27 .二叉树的镜像
  4. 剑指 Offer 28 .对称的二叉树
  5. 剑指 Offer 32 - I 从上到下打印二叉树
  6. 剑指 Offer 32 - II 从上到下打印二叉树 II
  7. 剑指 Offer 32 - III 从上到下打印二叉树 III
  8. 剑指 Offer 33 .二叉搜索树的后序遍历序列
  9. 剑指 Offer 34 .二叉树中和为某一值的路径
  10. 剑指 Offer 36 .二叉搜索树与双向链表
  11. 剑指 Offer 37 .序列化二叉树
  12. 剑指 Offer 54 .二叉搜索树的第k大节点
  13. 剑指 Offer 55 - I 二叉树的深度
  14. 剑指 Offer 55 - II 平衡二叉树
  15. 剑指 Offer 68 - I 二叉搜索树的最近公共祖先
  16. 剑指 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的八道二叉树题目的整理。涉及递归调用+广度优先遍历。相关推荐

  1. 剑指offer十八之二叉树的镜像

    一.题目 操作给定的二叉树,将其变换为源二叉树的镜像.二叉树的镜像定义: 源二叉树 : 8/ \6 10/ \ / \5 7 9 11镜像二叉树:8/ \10 6/ \ / \11 9 7 5 二.思 ...

  2. 《LeetCode力扣练习》剑指 Offer 28. 对称的二叉树 Java

    <LeetCode力扣练习>剑指 Offer 28. 对称的二叉树 Java 一.资源 题目: 请实现一个函数,用来判断一棵二叉树是不是对称的.如果一棵二叉树和它的镜像一样,那么它是对称的 ...

  3. DayDayUp之Job:牛客网—算法工程师—剑指offer之66道在线编程(解决思路及其代码)——1~20

    DayDayUp之Job:牛客网-算法工程师-剑指offer之66道在线编程(解决思路及其代码)--01~20 目录 剑指offer--66道在线编程--01~20 1.二维数组中的查找某个targe ...

  4. DayDayUp之Job:牛客网—算法工程师—剑指offer之66道在线编程(解决思路及其代码)——41~66

    DayDayUp之Job:牛客网-算法工程师-剑指offer之66道在线编程(解决思路及其代码)--41~66 目录 剑指offer之66道在线编程--41~66 42.和为s的两个数字 43.左旋转 ...

  5. DayDayUp之Job:牛客网—算法工程师—剑指offer之66道在线编程(解决思路及其代码)——21~40

    DayDayUp之Job:牛客网-算法工程师-剑指offer之66道在线编程(解决思路及其代码)--21~41 目录 剑指offer之66道在线编程--21~41 21.栈的压入.弹出序列 22.从上 ...

  6. LeetCode Algorithm 剑指 Offer 28. 对称的二叉树

    剑指 Offer 28. 对称的二叉树 Ideas 一开始想的有问题,看了例子以为对称二叉树的中序遍历序列是回文数组,然后就用这么写了,结果到第192个测试用例[1,2,2,2,null,2]就失败了 ...

  7. 【LeetCode】剑指 Offer 28. 对称的二叉树

    [LeetCode]剑指 Offer 28. 对称的二叉树 文章目录 [LeetCode]剑指 Offer 28. 对称的二叉树 一.递归 一.递归 对称二叉树定义:对于书中任意两个对称结点 L 和 ...

  8. 剑指offer——复习1:二叉树三种遍历方式的迭代与递归实现

    剑指offer--复习1:二叉树三种遍历方式的迭代与递归实现 20180905更新:这个博客中的解法不是很好,看相应的LeetCode题目笔记~~~ 我感觉此博客中的说法更容易让人理解:https:/ ...

  9. 最新算法校招编程-剑指offer、Leetcode常考题目及解法分享

    本资源整理了BAT.TMD等互联网算法岗校招面试过程中常考的LeetCode和剑指offer编程题:此外,还整理了部分百度.腾讯.阿里.今日头条相关的面试经验,对于正准备校招面试的同学非常值得参考复习 ...

最新文章

  1. python学习--基础
  2. java springcloud版b2b2c社交电商spring cloud分布式微服务(十三)断路器聚合监控(Hystrix Turbine)...
  3. 计算机网络的组成相关,计算机网络的组成
  4. linux内核加载卡主,请教mx6,linux3.0.35,tf卡能启动uboot但是无法加载内核问题
  5. 路痴的单身小菡 BFS求最短路径+DFS求路径数
  6. 优雅地在Mac+Valet环境下本地部署phphub
  7. linux运维和3dmax哪个简单,牛逼运维常用的工具系列-2
  8. java基础—多线程下的单例设计模式的安全问题
  9. Vue生命周期通俗理解
  10. (转)Uncaught TypeError: Cannot set property 'innerHTML' of null
  11. [包计划] create-react-app
  12. Codeforces.741D.Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree 思路)
  13. 网络系统设计的一般步骤
  14. 手机定位折腾记(1):安卓手机的网络定位与NetworkLocation.apk
  15. jvm的内存回收机制
  16. matlab 实现马赫带效应,图像上机实验.doc
  17. android如何增加北斗定位,安卓手机怎么设置北斗导航图文教程
  18. 那些拿到腾讯、阿里等大厂offer的人,都有这个共同点
  19. 毕业设计/论文答辩演讲稿通用模板
  20. android 仿微信来电_仿MIUI、微信来电通知无法解决通知折叠到通知列表

热门文章

  1. servlet的url-pattern匹配规则
  2. java jackson2.6_Jackson 2 - Convert Java Object to JSON and JSON String to Object
  3. 【多目标跟踪任务——评价指标】
  4. MOOC 数据结构 | 4. 树(中)
  5. 编写程序,将一年中 12 个月,建立一个枚举类型数据,并对其进行调用
  6. miui12超级壁纸怎么设置?
  7. Ubuntu18.04 小米游戏本最早一代 双硬盘 安装 过程记录
  8. Pytorch有关学习率的使用总结
  9. 蛤蜊丝瓜汤怎么做 蛤蜊丝瓜汤的做法
  10. 韩顺平 数据结构与算法 (12_3) 树结构应用部分_赫夫曼编码(思路)