找树左下角的值
递归法: 比较复杂, 直接拉代码:
class Solution {
private int Deep = -1;
private int value = 0;
public int findBottomLeftValue(TreeNode root) {
value = root.val;
findLeftValue(root,0);
return value;
}
private void findLeftValue (TreeNode root,int deep) {
if (root == null) return;
if (root.left == null && root.right == null) {
if (deep > Deep) {
value = root.val;
Deep = deep;
}
}
if (root.left != null) findLeftValue(root.left,deep + 1);
if (root.right != null) findLeftValue(root.right,deep + 1);
}
}
迭代法: 这个是很秒的, 左下角的值正好就是最后一层的第一个值, 所以直接peek就行了
class Solution {
public int findBottomLeftValue(TreeNode root) {
//迭代法定义一个队列
Queue<TreeNode> que = new LinkedList<>();
if(root == null){
return 0;
}
que.offer(root);
int res = 0;
while(!que.isEmpty()){
int size = que.size();
//左下角的值, 就是最后一层第一个
int res = que.peek().val;
while(size-- > 0){
TreeNode cur = que.poll();
if(cur.left != null){
que.offer(cur.left);
}
if(cur.right != null){
que.offer(cur.right);
}
}
}
return res;
}
}
路径总和
递归法, 用前序就行
思路: 每次遍历节点, 就要targetSum -= root.val, 遍历到叶子节点, 同时sum = 0时, 说明找到了路径
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null){
return false;
}
//每次遍历一个节点, 减去节点的val
targetSum -= root.val;
//中, 就是遍历到叶子节点时, 看最后值是否为0
if(root.left == null && root.right == null){
return targetSum == 0;
}
//继续递归, 不要让空节点进入递归
if(root.left != null){
boolean left = hasPathSum(root.left, targetSum);
//判断有没有找到
if(left) return true;
}
if(root.right != null){
boolean right = hasPathSum(root.right, targetSum);
//判断有没有找到
if(right) return true;
}
return false;
}
}
//精简版:
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null){
return false;
}
if(root.left == null && root.right == null){
return targetSum == root.val;
}
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}
}
迭代法:
定义两个栈, 一个栈用来遍历和之前的一样, 另一个栈用来收集sum, 和层序遍历的区别就是, 只要保证判断在叶子节点时, sum==targetSum, 就return true, 否则在while循环外面return false
路径总和II
前序, 和之前的找出所有路径有点相似, 但是多了回溯的思想
class Solution {
List<List<Integer>> res = new LinkedList<>();
Deque<Integer> path = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
dfs(root, targetSum);
return res;
}
public void dfs(TreeNode root, int targetSum){
if(root == null){
return;
}
先把根节点数值放在队列, 然后定义targetSum
path.offer(root.val);
targetSum -= root.val;
if(root.left == null && root.right == null && targetSum == 0){
//因为上面定义的list是公用的, 所以要里面创建下
res.add(new LinkedList<Integer>(path));
}
//继续递归
dfs(root.left, targetSum);
dfs(root.right, targetSum);
//这里需要回溯, 把path给poll出来
path.pollLast();
}
}
从前序与中序遍历序列构造二叉树
- 首先创建一个HashMap, 然后遍历保存中序序列
- 然后solution方法内return(preorder, 0, preorder.length, inorder, 0, inorder.length)左闭右开
- 创建递归方法, 因为return参数是左闭右开, 所有终止条件是>=和<=
- 先传入根节点, 然后根据下图定义inorder里的根节点位置pIndex = map.get(rootVal)
- 最后调用递归, left传入前序左子树参数, 和中序左子树参数, right同理
- 最后返回root
class Solution {
//*可选,因为树中没有重复元素,所以,可以开始用哈希表存储inorder的值和对应的索引
Map<Integer, Integer> inorderMap = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
//先把中序数组遍历放到map里面
for(int i = 0; i < inorder.length; i++){
inorderMap.put(inorder[i], i);
}
//return递归方法, 这里就是前序数组和中序数组的左右
//我这里对于边界的定义是左闭右开, 要注意
return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
}
//因为是造树, 所以要递归方法要return TreeNode
public TreeNode build(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd){
//先写个结束条件, 符合左闭右开
if(inStart > inEnd || preStart > preEnd){
return null;
}
//导入根节点
int rootVal = preorder[preStart];
TreeNode root = new TreeNode(rootVal);
//定义中序Index根节点
int index = inorderMap.get(rootVal);
开始递归
root.left = build(preorder, preStart + 1, index - inStart + preStart,
inorder, inStart, index - 1);
root.right = build(preorder, index - inStart + preStart + 1, preEnd,
inorder, index + 1, inEnd);
return root;
}
}
中序和后序构造二叉树
五步走:
- 后序数组为0, 空节点
- 后续数组最后一个元素为节点元素
- 寻找中序数组位置, 做切割点
- 切中序数组
- 切后序数组
- 递归处理左区间右区间
-
class Solution { //*可选,因为树中没有重复元素,所以,可以开始用哈希表存储inorder的值和对应的索引 Map<Integer, Integer> inorderMap = new HashMap<>(); public TreeNode buildTree(int[] inorder, int[] postorder) { for(int i = 0; i < inorder.length; i++){ inorderMap.put(inorder[i], i); } return build(inorder, 0, inorder.length - 1, postorder, 0, postorder.length - 1); } public TreeNode build(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd){ //最后写递归出口,base case if(inStart > inEnd || postStart > postEnd){ return null; } //1.确定根节点 int rootVal = postorder[postEnd]; //1.1做出根节点 TreeNode root = new TreeNode(rootVal); int index = inorderMap.get(rootVal); //2.1计算inorder中左子树的数目,以此确定后序中左右子树的边界 int num_left_tree = index - inStart; //3.递归构造左右子树 root.left = build(inorder, inStart, index - 1, postorder, postStart, postStart + num_left_tree - 1); root.right = build(inorder, index + 1, inEnd, postorder, postStart + num_left_tree, postEnd - 1); return root; } }