二叉树结点的深度是指当前结点到根节点的海拔;前序求深度
二叉树结点的高度是当前结点到最远叶子结点的海拔;后序求高度
110. 平衡二叉树
题目链接:. - 力扣(LeetCode)
平衡二叉树:所有结点左右子树深度相差不超过1
思路:因为是所有结点的深度,所以可以推卸责任,也就是可以递归
1. 确定递归返回值和参数,返回值为结点深度,如果以该结点为根的子树不是平衡二叉树就返回-1,作为标记;
2. 终止条件,结点为null返回0;
3. 推卸责任,把任务推给左孩子右孩子,让他们返回-1或深度,根据他们返回的值,如果左孩子和右孩子深度差值大于1,就返回-1,也算一个终止条件
递归法
public int isTrue(TreeNode node) {
if(node == null) return 0;
int leftHeight = isTrue(node.left);//推卸责任
if(leftHeight == -1)return -1;
int rightHeight = isTrue(node.right);
if(rightHeight == -1)return -1;
if(Math.abs(leftHeight - rightHeight) > 1) return -1;
else return 1 + Math.max(leftHeight,rightHeight);
}
257. 二叉树的所有路径
题目链接:. - 力扣(LeetCode)
明确题目: 返回从根节点到叶子结点的所有路径: ["1->2","1->4->8"]
思路:
1. 递归回溯,一个集合放路径(支持回溯),一个集合放路径结果
- 参数返回值: 参数为结点和集合路径,返回值为空
- 终止条件,结点左右结点为空
- 回溯: 推卸责任给孩子后,再从集合路径中取出该结点
- 推卸责任: 如果左右孩子不为空,就走他们
public void traversal(TreeNode node,List<String> path) {
path.add(node.val + "");//中;中写在这里可以让最后一个结点也加进路径中
if(node.left == null && node.right == null) {
String paths = path.stream().collect(Collectors.joining("->"));
result.add(paths);
}
if(node.left != null) {
traversal(node.left, path);//左
path.remove(path.size()-1);
}
if(node.right != null) {
traversal(node.right, path);//右
path.remove(path.size()-1);
}
}
他是从上到下,所以用前序遍历
同理,回溯也就是恢复现场(c++)
void traversal(TreeNode* cur, string path, vector<string>& result) {
path += to_string(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中
if (cur->left == NULL && cur->right == NULL) {
result.push_back(path);
return;
}
if (cur->left) {
path += "->";
traversal(cur->left, path, result); // 左
path.pop_back(); // 回溯 '>'
path.pop_back(); // 回溯 '-'
}
if (cur->right) {
path += "->";
traversal(cur->right, path, result); // 右
path.pop_back(); // 回溯'>'
path.pop_back(); // 回溯 '-'
}
}
2. 迭代法,还原递归
public List<String> binaryTreePaths(TreeNode root) {
// traversal(root,path);
Deque<String> paths = new LinkedList<>();
Deque<TreeNode> deque = new LinkedList<>();
if(root != null)deque.push(root);
paths.push(String.valueOf(root.val));
while(!deque.isEmpty()) {
TreeNode mid = deque.pop();//中结点
String path = paths.pop();//取出结点对应路径
if(mid.left == null && mid.right == null) {
result.add(path);
}
if(mid.right != null) {//右
deque.push(mid.right);
paths.push(path + "->" + String.valueOf(mid.right.val));
}
if(mid.left != null) {//左
deque.push(mid.left);
paths.push(path + "->" + String.valueOf(mid.left.val));
}
}
return result;
}
用两个栈,一个遍历,一个存路径;遍历用前序遍历
取出的路径加上孩子,遇到叶子就加到结果里;其实是用栈保存了某层的路径,跟递归是一样的
404.左叶子之和
题目链接:. - 力扣(LeetCode)
思路:左叶子就是叶子结点,同时也是左结点;
1. 可以用递归实现
- 参数和返回值: 返回值为左结点之和,参数为结点
- 终止条件: 如果当前结点的左结点不为空,并且左结点的左右孩子为空,就返回左结点的值加上左右孩子的左叶子之和;否则就返回左右孩子的左叶子之和
- 推卸责任: 终止条件里面的左右孩子的左叶子之和
public int sumLeftLeaves(TreeNode root) {
if(root == null) return 0;
TreeNode left = root.left;
TreeNode right = root.right;
int sum = 0;
//是左叶子
if(left != null && left.left == null && left.right == null) {
sum = left.val;
}
return sum + sumLeftLeaves(left) + sumLeftLeaves(right);
}
2. 迭代法:(层序遍历)
对左结点进行判断处理
public int sumOfLeftLeaves(TreeNode root) {
if(root == null) return 0;
int sum = 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
int size = queue.size();
for(int i=0;i<size;i++) {
TreeNode node = queue.poll();
if(node.left != null) {
queue.offer(node.left);
if(node.left.left == null && node.left.right == null) sum += node.left.val;
}
if(node.right != null) queue.offer(node.right);
}
}
return sum;
// return sumLeftLeaves(root);
}
222.完全二叉树的节点个数
题目链接:. - 力扣(LeetCode)
完全二叉树是满二叉树从下到上,从右到左拿走一些结点
思路:
1. 普通: 可以用迭代法,通用求二叉树结点个数;层序遍历,出队一个就把计数加一
层序遍历(迭代法)
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
int size = queue.size();
for(int i=0; i<size; i++) {
TreeNode node = queue.poll();
result++;
if(node.left != null) queue.offer(node.left);
if(node.right != null) queue.offer(node.right);
}
}
2. 普通:递归法,把责任推给左右孩子,让他们返回结点数,也就是后续遍历,左右中
int getNodesNum(TreeNode* cur) {
if (cur == NULL) return 0;
int leftNum = getNodesNum(cur->left); // 左
int rightNum = getNodesNum(cur->right); // 右
int treeNum = leftNum + rightNum + 1; // 中
return treeNum;
}
3. 递归法,利用完全二叉树里面有满二叉树,满二叉树结点的计算是 2<<h-1 ;
递归函数要做的是算满二叉树的结点数
- 返回值和参数: 返回值为结点数目,参数为结点
- 终止条件: 结点为null
- 推卸责任的过程: 就是把本层要做的推给左右孩子那一层;
需要一个判断,如果以当前为根的子树是满二叉树就根据高度计算结点数返回,如果不是,就推卸责任给孩子结点
需要孩子结点把他的结点数从下到上返回给父亲,所以用后序遍历,左右中
public int countNodess(TreeNode node) {
if(node == null) return 0;
int leftNode = 0,rightNode = 0;
TreeNode left = node.left;
TreeNode right = node.right;
while(left != null) {
left = left.left;
leftNode++;
}
while(right != null) {
right = right.right;
rightNode++;
}
if(leftNode == rightNode) return (2 << leftNode)-1;
int leftTreeNum = countNodess(node.left);//左
int rightTreeNum = countNodess(node.right);//右
return leftTreeNum + rightTreeNum + 1;//中
}
其中判断是否为满二叉树用到完全二叉树的性质,只要最左孩子的深度等于最右孩子的深度,那他就是满二叉树,否则就是两个孩子的结点数+1;