所用代码 java
平衡二叉树 LeetCode 110
题目链接:平衡二叉树 LeetCode 110 - 简单
思路
使用递归遍历,判断左右子树传回来的高度差是否大于1
若子树高度差都大于1了,就肯定不是平衡二叉树,我们就定义一个返回变量 -1,这个返回变量每次往上传递的话我们就知道了子树是否是平衡二叉树。
若子树高度差小于等于1,那就是平衡二叉树,我们只需要继续累计高度。
class Solution {
public boolean isBalanced(TreeNode root) {
int flag = traversal(root);
if (flag == -1) return false;
else return true;
}
// 后序遍历才能求高度
public int traversal(TreeNode node){
if (node == null) return 0;
// 左
int left = traversal(node.left);
// 若左子树不是平衡二叉树就向上返回,此树就一定不是平衡二叉树
if (left == -1) return -1;
// 右
int right = traversal(node.right);
// 右子树不是平衡二叉树也返回
if (right == -1) return -1;
// 中
if (Math.abs(left - right) > 1){
// 非平衡二叉树,返回标记
return -1;
}else {
// 平衡二叉树的情况就返回此树的高度,高度肯定取的是最大高度
return 1 + Math.max(left, right);
}
}
}
层序遍历: 会多求很多次高度,导致重复计算,速度更慢
class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
Deque<TreeNode> deque = new ArrayDeque<>();
deque.offer(root);
while (!deque.isEmpty()){
int size = deque.size();
for (int i = 0; i < size; i++) {
TreeNode node = deque.poll();
// 判断左右子树高度差是否相差大于1
if (Math.abs(getHeight(node.left) - getHeight(node.right)) > 1){
return false;
}
if (node.left != null) deque.offer(node.left);
if (node.right != null) deque.offer(node.right);
}
}
return true;
}
public int getHeight(TreeNode node){
int deep = 0;
Deque<TreeNode> deque = new ArrayDeque<>();
if (node != null) deque.offer(node);
while (!deque.isEmpty()){
int size = deque.size();
deep++;
for (int i = 0; i < size; i++) {
TreeNode n = deque.poll();
if (n.left != null) deque.offer(n.left);
if (n.right != null) deque.offer(n.right);
}
}
return deep;
}
}
总结
当我们既需要求二叉树的高度,又需要返回一个结果(确定他处于某种状况),如是不是平衡二叉树,就可以多返回一个定值,如-1,通过这个值就可以做到两者同时判断。
二叉树的所有路径 LeetCode 257
题目链接:二叉树的所有路径 LeetCode 257 - 简单
思路
先输出根,所以得用前序遍历,然后每一次需要输出一个箭头,需要一个StringBuilder来拼接
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
// 需保证传入的结点不为空,以免NPE
if (root == null) return res;
List<Integer> path = new ArrayList<>();
traversal(root, path, res);
return res;
}
// 前序
public void traversal(TreeNode node, List<Integer> path, List<String> res){
// 中
path.add(node.val);
// 到底叶子结点就拼接路径的值
if (node.left == null && node.right == null ) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < path.size() - 1; i++) {
sb.append(path.get(i));
sb.append("->");
}
// 最后一个数不用加->
sb.append(path.get(path.size() - 1));
// 拼接完之后加入list
res.add(sb.toString());
return;
}
// 左
if (node.left != null) {
traversal(node.left, path, res);
// 回溯,移除最后一个数
path.remove(path.size() - 1);
}
// 右
if (node.right != null) {
traversal(node.right, path, res);
// 回溯,移除最后一个数
path.remove(path.size() - 1);
}
}
}
迭代法: 使用栈来解决,一般为前序
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
// 需保证传入的结点不为空,以免NPE
if (root == null) return res;
// 一个结点栈,一个路径栈,两个栈处理逻辑一一对应 其实可以用一个栈来解决
Stack<TreeNode> stNode = new Stack<>();
Stack<String> stPath = new Stack<>();
stNode.push(root);
stPath.push(String.valueOf(root.val));
// 中 右 左 进栈,则为前序遍历
while (!stNode.isEmpty()){
// 弹出栈的结点和对应的路径
TreeNode node = stNode.pop();
String path = stPath.pop();
// 中 - 如果到达叶子结点,就把该路径加入结果
if (node.left == null && node.right == null){
res.add(path);
}
// 右 - 对应的栈添加结点和-> => 1 ->3
if (node.right != null){
stNode.push(node.right);
stPath.push(path + "->" + node.right.val);
}
// 左
if (node.left != null){
stNode.push(node.left);
stPath.push(path + "->" + node.left.val);
}
}
return res;
}
}
总结
使用两个list来存数据,一个存所经历路径的值,另一个存结果可以更方便的得出结果。
另外一个就是我们进行递归的时候要知道每次都有回溯的过程,把回溯写在递归后,就能使每次存的值减少。
左叶子之和 LeetCode 404
题目链接:左叶子之和 LeetCode 404 - 简单
思路
无。
我们需要在叶子节点的父节点收集值,所以到叶子结点就返回0,直到父结点再判断该叶子结点是不是左孩子
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
return traversal(root);
}
// 后序遍历
public int traversal(TreeNode node){
if (node == null) return 0;
// 到叶子结点也返回0
// 因为叶子结点的左孩子之和就为0
if (node.left == null && node.right == null) return 0;
// 左
int leftNum = traversal(node.left);
// 若左子树有左结点,且结点为叶子树结点,该值就是需要的值
if (node.left != null && node.left.left == null && node.left.right == null){
leftNum = node.left.val;
}
// 右
int rightNum = traversal(node.right);
// 中
int sum = leftNum + rightNum;
return sum;
}
}
迭代法:
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
int sum = 0;
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root);
// 迭代前序比较方便,中左右=>入栈顺序:右左中
while (!stack.isEmpty()){
TreeNode node = stack.pop();
if (node.left != null && node.left.left == null && node.left.right == null){
sum += node.left.val;
}
if (node.left != null) stack.push(node.left);
if (node.right != null) stack.push(node.right);
}
return sum;
}
}
层序遍历:
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
int sum = 0;
Deque<TreeNode> deque = new ArrayDeque<>();
deque.offer(root);
while (!deque.isEmpty()){
int size = deque.size();
for (int i = 0; i < size; i++) {
TreeNode node = deque.poll();
// 从左孩子的父节点入手
if (node.left != null && node.left.left == null && node.left.right == null){
sum += node.left.val;
}
if (node.left != null) deque.offer(node.left);
if (node.right != null) deque.offer(node.right);
}
}
return sum;
}
}
总结
本题的关键就是找到需要的结点,也就是我们的目标孩子的父节点,所以这句话就是最关键的一句。
if (node.left != null && node.left.left == null && node.left.right == null){
sum += node.left.val;
}