从中序和后序遍历序列构造二叉树
思路
具体思路见代码or思维导图
自己刚开始写时,思路非常混乱,应该用文字理清思路,在代码中注释后,再一步步想办法如何用代码诠释这些文字
后来各种小的报错
root.left和root.right不需要再次定义!在TreeNode的定义中已经将它们的定义写好了。
代码
class Solution {
Map<Integer,Integer> map;
TreeNode traversal(int[] inorder,int inBegin,int inEnd,int[] postorder,int postBegin,int postEnd){
// 终止条件
if (inBegin >= inEnd || postBegin >= postEnd){
return null;
}
// 单层逻辑
// 1.找到后序遍历序列最后一个元素在中序遍历队列中的位置
int rootIndex = map.get(postorder[postEnd - 1]);
// 创建节点
TreeNode root = new TreeNode(inorder[rootIndex]);
// 2.将中序队列分为中左区间和中右区间
// 3.将后序队列按照中序队列的长度,分为后左区间和后右区间
int lenOfLeft = rootIndex - inBegin;
// 4.递归遍历
// root.left和root.right,本来就是TreeNode类型,不需要再次定义
root.left = traversal(inorder,inBegin,rootIndex,
postorder,postBegin,postBegin + lenOfLeft);
// root.left = traversal(inorder, inBegin, rootIndex,
// postorder, postBegin, postBegin + lenOfLeft);
root.right = traversal(inorder, rootIndex + 1, inEnd,
postorder, postBegin + lenOfLeft, postEnd - 1);
return root;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
// 左闭右开区间
map = new HashMap<>();
for (int i = 0;i < inorder.length;i++){
map.put(inorder[i],i);
}
return traversal(inorder,0,inorder.length,postorder,0,postorder.length);
}
}
最大二叉树
链接: 654.最大二叉树
思路
思路非常简单
找到序列中的最大值,创建节点,然后再遍历最大值分隔出的左区间和右区间,用root.left和root.right进行接收
注意:用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,这样可以节约时间和空间上的开销。
PS:因为题目给出的函数入口只有int[] nums;所以我们又定义了一个遍历函数。
代码
class Solution {
TreeNode traversal(int[] nums,int begin,int end){
if (begin >= end) return null;
int max = begin;
// 找到序列中的最大值
for (int i = begin + 1;i < end;i++){
if (nums[i] > nums[max]){
max = i;
}
}
// 创建节点
TreeNode root = new TreeNode(nums[max]);
// 循环遍历左区间和右区间
root.left = traversal(nums,begin,max);
root.right = traversal(nums,max+ 1,end);
return root;
}
public TreeNode constructMaximumBinaryTree(int[] nums) {
// 左闭右开区间
return traversal(nums,0,nums.length);
}
}
合并二叉树
链接: 617.合并二叉树
感悟
代码并不困难,用代码把自己的思路写下来即可,如果有哪里不合适,说明自己的思维不对,需要吸取参考别人的思路。
写代码前,先把自己的思路分块用注释标注好,然后再去写这一块内容
代码
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) return root2;
if (root2 == null) return root1;
root1.val += root2.val;
root1.left = mergeTrees(root1.left,root2.left);
root1.right = mergeTrees(root1.right,root2.right);
return root1;
}
}
二叉搜索树中的搜索
链接: 700.二叉搜索树中的搜索
思路
将自己的思路写下来即可
代码
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if (root == null || root.val == val) return root;
TreeNode result = null;
if (val > root.val) result = searchBST(root.right,val);
if (val < root.val) result = searchBST(root.left,val);
return result;
}
}
验证二叉搜索树
链接: 98.验证二叉搜索树
思路
思路一
一定要记住:对于二叉搜索树,中序遍历得到的数组,一定是有序数组,递增(不可以有相同元素)
思路二
边中序遍历,边比较。设置一个变量记录遍历时的前一个节点,比较前一个节点与当前节点的大小,不符合递增情况则false,遍历结束返回true
代码
//转化成列表的形式
class Solution {
List<Integer> list = new ArrayList<>();
void traversal(TreeNode root){
if (root == null) return;
traversal(root.left);
list.add(root.val);
traversal(root.right);
}
public boolean isValidBST(TreeNode root) {
traversal(root);
for (int i = 1;i < list.size();i++){
if (list.get(i) <= list.get(i - 1)) return false;
}
return true;
}
}
//边中序遍历边比较
class Solution {
TreeNode pre = null;
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
boolean left = isValidBST(root.left);
if (pre != null && pre.val >= root.val) return false;
pre = root;
boolean right = isValidBST(root.right);
return left && right;
}
}
小tips:
在写完代码后,至少要写三个测试用例验证
两个系统给的,一个自己想想有无特殊情况。
二叉搜索树的最小绝对差
链接: 530.二叉搜索树的最小绝对差
思路
二叉搜索树中序遍历有序,所以最小绝对差一定是相邻两个元素相减。二叉搜索树中序遍历有序,所以最小绝对差一定是相邻两个元素相减。
代码
class Solution {
List<Integer> list = new ArrayList<>();
void traversal(TreeNode root){
if (root == null) return;
traversal(root.left);
list.add(root.val);
traversal(root.right);
}
public int getMinimumDifference(TreeNode root) {
traversal(root);
// 因为要比较大小,不可以简单地为result赋一个值
int result = Integer.MAX_VALUE;
if (list.size() < 2) return 0;
for (int i = 1;i < list.size();i++){
result = Math.min(result,list.get(i) - list.get(i - 1));
}
return result;
}
}
//边中序遍历边比较最小绝对差
class Solution {
int result = Integer.MAX_VALUE;
TreeNode pre = null;
void traversal(TreeNode cur){
if (cur == null) return;
traversal(cur.left);
if (pre != null){
result = Math.min(result,cur.val - pre.val);
}
pre = cur;
traversal(cur.right);
}
public int getMinimumDifference(TreeNode root) {
traversal(root);
return result;
}
}
二叉搜索树中的众数
链接: 501.二叉搜索树中的众数
思路
二叉搜索树有其特殊性,在有相同值的二叉树中,该二叉树中序遍历后得到的序列是不递减的。
在前面的题目中,我们知道如果不把二叉树转化成序列的形式,可以创建前一个节点pre,利用pre和cur的关系来进行比较。
本道题目,我想到了求出maxCount的方法,但如何将多个众数加入序列中,没有思路,这一点需要学习。
可以在比较count和maxCount时,对结果集进行操作,每次比较时,说明没有达到最大出现次数,将原有结果清空,加入最新结果。如果count=maxCount时,原有结果保留的同时,加入出现次数相同的元素
代码
class Solution {
List<Integer> reList;
int count;
int maxCount;
TreeNode pre;
public int[] findMode(TreeNode root) {
reList = new ArrayList<>();
count = 0;
maxCount = 0;
pre = null;
findMode1(root);
int[] result = new int[reList.size()];
for (int i = 0;i < reList.size();i++){
result[i] = reList.get(i);
}
return result;
}
void findMode1(TreeNode cur){
if (cur == null) return;
findMode1(cur.left);
if (pre == null || pre.val != cur.val){
count = 1;
}else{
count++;
}
//重要!!!!
if (count > maxCount){
maxCount = count;
reList.clear();
reList.add(cur.val);
}else if(count == maxCount){
reList.add(cur.val);
}
// 一定不要忘记移动pre呀!三四次了!
pre = cur;
findMode1(cur.right);
return;
}
}