动态规划理解
需要使用到动态规划算法的问题都是原问题可以拆分为小问题,而大的问题是受小问题影响的。
树型动态规划通用公式
1.首先分析出要满足当前要求需要从左右孩子获取到什么信息。
2.将需要用到的信息进行封装(如果只有单条数据就不用封装了)
3.编写递归函数 函数的返回值就是2中封装的信息体
3.1在递归函数中首先写出最小问题的信息体并返回
3.2从左右子树获取它们的信息体
3.3通过左右子树获得的信息体来推算出自己的信息体并将其返回即可
题1:判断二叉树是否是满二叉树
分析:
1.首先分析出要满足当前要求需要从左右孩子获取到说明信息。
需要知道当前树的高度和树的总节点数(2的height次方 - 1与总节点相等就是满二叉树)
2.将需要用到的信息进行封装(如果只有单条数据就不用封装了)
封装树的高度和总节点数
3.编写递归函数 函数的返回值就是2中封装的信息体
3.1在递归函数中首先写出最小问题的信息体并返回
最小问题:树为空 ==> 树的高度为0 数的总节点数为0
3.2从左右子树获取它们的信息体
直接调用递归函数获取
3.3通过左右子树获得的信息体来推算出自己的信息体并将其返回即可
1.高度:当前节点的高度 = 左右孩子节点的高度较大的那一个高度 + 1
2.总节点数:当前节点的总节点数 = 左右孩子的节点数之和
public boolean isFullTree(Nodes root){
if (root == null)
return true;
//写递归函数
Data result = process(root);
return result.nodeNum == (1 << result.height) - 1;
}
//封装信息体
public static class Data{
int height;
int nodeNum;
public Data(int height, int nodeNum) {
this.height = height;
this.nodeNum = nodeNum;
}
}
//递归函数
public Data process(Nodes nodes){
if (nodes == null)
return new Data(0, 0);
Data leftData = process(nodes.getLeft());//左树返给我的信息
Data rightData = process(nodes.getRight());//右树返给我的信息
//从左右树返给我的信息进行处理从而得到自己的信息
int height = Math.max(leftData.height, rightData.height) + 1;
int nodeNum = leftData.nodeNum + rightData.nodeNum + 1;
return new Data(height, nodeNum);
}
题2:判断二叉树是否是平衡二叉树
分析:
1.首先分析出要满足当前要求需要从左右孩子获取到说明信息。
需要知道当前树的左右孩子是否是平衡二叉树 左右孩子的高度(左右孩子都是平衡二叉树并且左右孩子的高度差的绝对值小于等于1就是平衡二叉树)
2.将需要用到的信息进行封装(如果只有单条数据就不用封装了)
封装是否是平衡二叉树 和 树的高度
3.编写递归函数 函数的返回值就是2中封装的信息体
3.1在递归函数中首先写出最小问题的信息体并返回
最小问题:树为空 ==> 是平衡二叉树 高度为0
3.2从左右子树获取它们的信息体
直接调用递归函数获取
3.3通过左右子树获得的信息体来推算出自己的信息体并将其返回即可
1.是否是平衡二叉树:左右孩子都是平衡二叉树并且左右孩子的高度差的绝对值小于等于1就是平衡二叉树
2.树的高度:左右孩子中高度较高的高度 + 1
public boolean isBalanceTree(Nodes root){
if (root == null)
return true;
Data result = process(root);
return result.is;
}
//封装信息
public static class Data{
boolean is;
int height;
public Data(boolean is, int height) {
this.is = is;
this.height = height;
}
}
public Data process(Nodes node){
if (node == null)
return new Data(true, 0);
//获取左右子树的信息
Data leftData = process(node.getLeft());
Data rightData = process(node.getRight());
//处理自己的信息
boolean is = false;
int height;
//is为true的条件是 左右子树的is都为true 并且 它们的高度差小于等于1
if (leftData.is && rightData.is && Math.abs(leftData.height - rightData.height) <= 1)
is = true;
height = Math.max(leftData.height, rightData.height) + 1;
return new Data(is,height);
}
题3:判断二叉树是否是搜索二叉树
分析:
1.首先分析出要满足当前要求需要从左右孩子获取到说明信息。
需要知道当前树的左右孩子是否是搜索二叉树 左孩子的最大值 右孩子的最小值
2.将需要用到的信息进行封装(如果只有单条数据就不用封装了)
封装是否是搜索二叉树 和 树的最大最小值(由于递归的原因所有递归的参数要一致 所以左右孩子的最大最小值都要有)
3.编写递归函数 函数的返回值就是2中封装的信息体
3.1在递归函数中首先写出最小问题的信息体并返回
最小问题:树为空 ==> 由于最大最小值不好给出 所有直接返回null后面再做判断
3.2从左右子树获取它们的信息体
直接调用递归函数获取
3.3通过左右子树获得的信息体来推算出自己的信息体并将其返回即可
1.是否是搜索二叉树:满足一下条件就不是搜索二叉树
1.1.有左孩子 并且 左孩子的最大值大于等于了当前节点的value
1.2.有右孩子 并且 右孩子的最小值小于等于了当前节点的value
2.max:左孩子最大值、右孩子最大值、以及当前值中最大的
3.min:左孩子最小值、右孩子最小值、以及当前值中最小的
public boolean isSearchTree(Nodes root){
if (root == null)
return true;
//递归函数
Data data = process(root);
return data.is;
}
//封装信息
public static class Data{
boolean is;
int max;
int min;
public Data(boolean is, int max, int min) {
this.is = is;
this.max = max;
this.min = min;
}
}
public Data process(Nodes node){
if (node == null)
return null;//因为这里的最大最小值不好确定 所有先暂且返回null 但是后面就要进行判断了
//获取左右子树的信息
Data leftData = process(node.getLeft());
Data rightData = process(node.getRight());
//根据左右子树的信息加工自己的信息
int max = node.getValue();
int min = node.getValue();
if (node.getLeft() != null){
max = Math.max(leftData.max, max);
min = Math.min(leftData.min, min);
}
if (node.getRight() != null){
max = Math.max(rightData.max, max);
min = Math.min(rightData.min, min);
}
boolean is = true;
//说明情况下导致is变false 1.有左孩子 && 左孩子的最大值大于等于了node.value
// 2.有右孩子 && 右孩子的最小值小于等于了node.value
if (leftData != null && (leftData.max >= node.getValue()))
is = false;
if (rightData != null && (rightData.min <= node.getValue()))
is = false;
return new Data(is, max, min);
}
题1:给出一颗二叉树的两个节点(n1和n2),找到它们的第一个父节点
分析:
采用递归的方式从下向上的返回信息最后根节点返回的信息就是题解
制定边界:
1.如果自己是null 那么就返回null
2.如果自己是n1或者n2就返回自己
注:
1.其实1、2可以合并为 如果自己是null或者n1或者n2就返回自己
2.为什么要有第二条 因为当前节点的返回值不仅受左右孩子信息的影响 有时候还会受自己的信息影响比如说当自己的信息是n1或者n2的时候。
制定自己返回信息的规则:
1.如果左右孩子给我的信息都不为null 那就返回我自己 此时说明自己就是第一个公共的父节点 把自己返回后根据3就会一路返回到根
2.如果左右孩子都为null就返回null
3.如果左右孩子有一个为null有一个不为null 那就返回不为null的那个
public Nodes process(Nodes head,Nodes o1,Nodes o2){
if (head == null || head == o1 || head == o2)
return head;
//接收左右孩子返回的信息
Nodes leftData = process(head.getLeft(), o1, o2);
Nodes rightData = process(head.getRight(), o1, o2);
if (leftData != null && rightData != null)
return head;
return leftData != null ? leftData : rightData;
}