文章目录
1. 对称二叉树
101. 对称二叉树
- 递归
- 迭代
/*
* 1.递归法
* 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
* 内存消耗:39.5 MB, 在所有 Java 提交中击败了38.81%的用户
*/
public boolean isSymmetric1(TreeNode root) {
return compare(root.left , root.right);
}
private boolean compare(TreeNode left, TreeNode right) {
/* 1.左右都空,true
* 2.左右一个空,flase
* 3.左右不等,flase
* 4.内侧递归
* 5.外侧递归
*/
if( left == null && right == null ) return true;
if( left != null && right == null ) return false;
if( left == null && right != null ) return false;
if( left.val != right.val ) return false;
boolean l = compare(left.left, right.right);
boolean r = compare(left.right, right.left);
return l && r;
}
/**
* 迭代法使用普通队列
* 执行用时:1 ms, 在所有 Java 提交中击败了23.01%的用户
* 内存消耗:39.4 MB, 在所有 Java 提交中击败了50.90%的用户
*/
public boolean isSymmetric3(TreeNode root) {
Queue<TreeNode> deque = new LinkedList<>();
deque.offer(root.left);
deque.offer(root.right);
while (!deque.isEmpty()) {
TreeNode leftNode = deque.poll();
TreeNode rightNode = deque.poll();
if (leftNode == null && rightNode == null) {
continue;
}
// if (leftNode == null && rightNode != null) {
// return false;
// }
// if (leftNode != null && rightNode == null) {
// return false;
// }
// if (leftNode.val != rightNode.val) {
// return false;
// }
// 以上三个判断条件合并
if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
return false;
}
// 这里顺序与使用Deque不同
deque.offer(leftNode.left);
deque.offer(rightNode.right);
deque.offer(leftNode.right);
deque.offer(rightNode.left);
}
return true;
}
100. 相同的树
跟上面那题做法一样
/*
* 1. 迭代法
* 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
* 内存消耗:38.8 MB, 在所有 Java 提交中击败了34.52%的用户
*/
public boolean isSameTree1(TreeNode p, TreeNode q) {
if( p == null && q == null) return true;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(p);
queue.offer(q);
while(!queue.isEmpty()){
TreeNode n1 = queue.poll();
TreeNode n2 = queue.poll();
if(n1 == null && n2 == null) continue;
if(n1 == null || n2 == null || n1.val != n2.val) return false;
//System.out.println("n1:" + n1.val + ", n2:" + n2.val);
queue.offer(n1.left);
queue.offer(n2.left);
queue.offer(n1.right);
queue.offer(n2.right);
}
return true;
}
/*
* 递归法
* 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
* 内存消耗:38.8 MB, 在所有 Java 提交中击败了32.54%的用户
*/
public boolean isSameTree(TreeNode p, TreeNode q) {
return isSame(p, q);
}
public boolean isSame(TreeNode p, TreeNode q){
if(p == null && q == null) return true;
if(p == null || q == null || p.val != q.val) return false;
boolean isl = isSame(p.left, q.left);
boolean isr = isSame(p.right, q.right);
return isl && isr;
}
572. 另一棵树的子树
这题下线很低,上限很高
- 遍历每一个结点,每一个结点判断是否相等
- kmp算法
- 构造哈希,埃氏筛。不是给人做的
2. 平衡二叉树
110. 平衡二叉树
https://leetcode-cn.com/problems/balanced-binary-tree/
- 递归(如果不平衡就是-1)
- 迭代,没写
public boolean isBalanced(TreeNode root) {
return geth(root) != -1;
}
public int geth(TreeNode root) {
if(root == null) return 0;
int l = geth(root.left);
if(l == -1) return -1;
int r = geth(root.right);
if(r == -1) return -1;
if(Math.abs(l-r) > 1) return -1;
return Math.max(l, r) + 1;
}
3. 二叉树路径(回溯)
257. 二叉树的所有路径
https://leetcode-cn.com/problems/binary-tree-paths/
/* 1.迭代法
* 执行用时:17 ms, 在所有 Java 提交中击败了8.78%的用户
* 内存消耗:41.7 MB, 在所有 Java 提交中击败了18.41%的用户
*/
public List<String> binaryTreePaths(TreeNode root) {
List<String> result = new ArrayList<>();
if (root == null)
return result;
Stack<Object> stack = new Stack<>();
// 节点和路径同时入栈
stack.push(root);
stack.push(root.val + "");
while (!stack.isEmpty()) {
// 节点和路径同时出栈
System.out.println(stack.toString());
String path = (String) stack.pop();
System.out.println(path);
TreeNode node = (TreeNode) stack.pop();
// 若找到叶子节点
if (node.left == null && node.right == null) {
result.add(path);
}
//右子节点不为空
if (node.right != null) {
stack.push(node.right);
stack.push(path + "->" + node.right.val);
}
//左子节点不为空
if (node.left != null) {
stack.push(node.left);
stack.push(path + "->" + node.left.val);
}
}
return result;
}
/*
* 2.递归法
* 执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户
* 内存消耗:41.8 MB, 在所有 Java 提交中击败了9.35%的用户
*/
public List<String> binaryTreePaths1(TreeNode root) {
List<String> res = new ArrayList<>();
if (root == null) return res;
List<Integer> paths = new ArrayList<>();
traversal(root, paths, res);
return res;
}
private void traversal(TreeNode root, List<Integer> paths, List<String> res) {
paths.add(root.val);
if(root.left == null && root.right == null){//碰到叶子结点
StringBuilder sb = new StringBuilder();
for(int i=0; i<paths.size()-1; i++) {
sb.append(paths.get(i)).append("->");
}
sb.append(paths.get(paths.size()-1));
res.add(sb.toString());
return;
}
if(root.left != null){
traversal(root.left, paths, res);
paths.remove(paths.size()-1); //回溯
}
if(root.right != null){
traversal(root.right, paths, res);
paths.remove(paths.size()-1); //回溯
}
}
112. 路径总和
/*
* 递归法
* 1. targetSum减去路过的节点的值
* 2. 碰到叶子节点,判断targetSum是否等于0,等于0就返回true
* 3. 注意如果找到了提前告知,没找到先别bibi等最后return false
* 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
* 内存消耗:41.5 MB, 在所有 Java 提交中击败了11.62%的用户
*/
public boolean hasPathSum1(TreeNode root, int targetSum) {
if( root == null) return false;
targetSum -= root.val;
// 叶子结点
if (root.left == null && root.right == null) {
return targetSum == 0;
}
if(root.left != null){
boolean l = hasPathSum(root.left, targetSum);
if(l) return true;
}
if(root.right != null){
boolean r = hasPathSum(root.right, targetSum);
if(r) return true;
}
return false;
}
/*
* 简洁方法三行搞定
* 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
* 内存消耗:41.4 MB, 在所有 Java 提交中击败了20.47%的用户
*/
public boolean hasPathSum(TreeNode root, int targetSum) {
//1. 空头直接否
if( root == null) return false;
//2. 碰到叶子节点判断
if (root.left == null && root.right == null) return root.val == targetSum;
//3. 左右分支的并,有一条有就算有
return hasPathSum(root.left, targetSum-root.val) || hasPathSum(root.right, targetSum-root.val);
}
113. 路径总和 II
https://leetcode-cn.com/problems/path-sum-ii/
这题改了好几遍
/*
* 深度优先遍历
*/
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
dfs(root, 0, targetSum);
return res;
}
public void dfs(TreeNode root, int num, int sum) {
if( root == null ) return;
num += root.val;
list.add(root.val);
if( num == sum && root.left == null && root.right == null){
res.add(new ArrayList(list));
}
dfs(root.left, num, sum);
dfs(root.right, num, sum);
list.remove(list.size()-1);//要回溯
}
4. 二叉树最左(最右同理)
404. 左叶子之和
https://leetcode-cn.com/problems/sum-of-left-leaves/
/*
* 1.递归
* 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
* 内存消耗:39.6 MB, 在所有 Java 提交中击败了5.23%的用户
*/
public int sumOfLeftLeaves1(TreeNode root) {
if(root == null) return 0;
int suml = sumOfLeftLeaves1(root.left);
int sumr = sumOfLeftLeaves1(root.right);
int mid = 0;
if( root.left != null && root.left.left == null && root.left.right == null){
mid = root.left.val;
}
return mid + suml + sumr;
}
/*
* 2.迭代
* 执行用时:1 ms, 在所有 Java 提交中击败了13.01%的用户
* 内存消耗:39.1 MB, 在所有 Java 提交中击败了44.39%的用户
*/
public int sumOfLeftLeaves(TreeNode root) {
if(root == null) return 0;
Stack<TreeNode> stack = new Stack<> ();
stack.add(root);
int tosum = 0;
while(!stack.isEmpty()){
TreeNode node = stack.pop();
if( node.left != null && node.left.left == null && node.left.right == null){
tosum += node.left.val;
}
if( node.left != null) stack.add(node.left);
if( node.right != null) stack.add(node.right);
}
return tosum;
}
513. 找树左下角的值
https://leetcode-cn.com/problems/find-bottom-left-tree-value/
/*
* 1.层序遍历
* 执行用时:2 ms, 在所有 Java 提交中击败了18.65%的用户
* 内存消耗:40.7 MB, 在所有 Java 提交中击败了55.58%的用户
* 其实不需要List存每一个数,len--那一步用个i,i==0的时候记录一下就好了
*/
public int findBottomLeftValue1(TreeNode root) {
//1.如果root为空,返回0
if(root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
//2.把根节点放入队列
queue.offer(root);
List<Integer> temp = new ArrayList<Integer>();
while(!queue.isEmpty()){
temp.clear();
int len = queue.size();
while(len-->0){
TreeNode n = queue.poll();
temp.add(n.val);
if(n.left != null) queue.add(n.left);
if(n.right != null) queue.add(n.right);
}
}
return temp.get(0);
}
/*
* 2.递归,需要两个量,当前最大深度,和最终值
* ① 如果当前 叶子节点 非空 且比 当前最大深度深,则最终值改为当前点的值,最大深度改为当前深度
* ② 如何确定是左边的点?递归先左后右
* 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
* 内存消耗:40.9 MB, 在所有 Java 提交中击败了41.03%的用户
*/
int Deep = -1;
int ans = 0;
public int findBottomLeftValue(TreeNode root) {
if( root == null ) return 0;
findbigleft(root, 0);
return ans;
}
public void findbigleft(TreeNode root, int deep){
//if( deep > Deep ) ans = root.val;
if( root.left == null && root.right == null){
if( deep > Deep ){
ans = root.val;
Deep = deep;
}
}
if(root.left != null) findbigleft(root.left, deep+1);
if(root.right != null) findbigleft(root.right, deep+1);
}
5. 构造二叉树
106. 从中序与后序遍历序列构造二叉树
https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
public TreeNode buildTree(int[] inorder, int[] postorder) {
int inlen = inorder.length;
int postlen = postorder.length;
return builder(inorder, 0, inlen-1, postorder, 0, postlen-1);
}
/**
*
* @param inorder 中序数组
* @param inl 当前处理的中序数组段的起始位置
* @param inr 当前处理的中序数组段的末尾位置
* @param postorder 后序数组
* @param postl 当前处理的后序数组段的起始位置
* @param postr 当前处理的后序数组段的末尾位置
*/
public TreeNode builder(int[] inorder, int inl, int inr, int[] postorder, int postl, int postr) {
//1. 空的返回null
if(inl > inr) return null;
System.out.print("前序排列为:");show(inorder, inl, inr);System.out.print("; ");
System.out.print("后序排列为:");show(postorder, postl, postr);System.out.print("\n");
//2. 只有一个值,返回他本身
if(inl == inr) return new TreeNode(inorder[inl]);
//3. 如果不只一个,后序最后一个是root
TreeNode root = new TreeNode(postorder[postr]);
//4. 找到root.val在中序中的位置(以左右子树结点个数分割后序)
int rootindex = 0;
for(int i=inl; i<=inr; i++) {
if(inorder[i] == root.val) {
rootindex = i;
break;
}
}
//5. 递归左子树:
// 中序起始位置不变,中序末尾位置变到rootindex-1
// 后序起始位置不变,后序末尾位置变为(后序起始位置+中序当前序列个数-1)
// 中序当前序列个数 = rootindex - inl
root.left = builder(inorder, inl, rootindex-1,
postorder, postl, postl+(rootindex-inl-1));
//6. 递归右子树
// 中序起始位置变为rootindex+1,中序末尾位置不变inr
// 后序起始位置变为(后序起始位置+前序个数),后序末尾位置变为postr-1
// 中序当前序列个数 = rootindex-inl
root.right = builder(inorder, rootindex+1, inr,
postorder, postl+(rootindex-inl), postr-1);
//7. 返回root
return root;
}
105. 从前序与中序遍历序列构造二叉树
https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
public TreeNode buildTree(int[] preorder, int[] inorder) {
int prelen = preorder.length;
int inlen = inorder.length;
return builder(preorder, 0, prelen-1, inorder, 0, inlen-1);
}
/**
*
* @param inorder 前序数组
* @param inl 当前处理的前序数组段的起始位置
* @param inr 当前处理的前序数组段的末尾位置
* @param postorder 中序数组
* @param postl 当前处理的中序数组段的起始位置
* @param postr 当前处理的中序数组段的末尾位置
*/
public TreeNode builder(int[] preorder, int prel, int prer,
int[] inorder, int inl, int inr) {
//1. 空的返回null
if(inl > inr || prel > prer) return null;
System.out.println(prel);
System.out.print("中序排列为:");show(inorder, inl, inr);System.out.print("; ");
System.out.print("前序排列为:");show(preorder, prel, prer);System.out.print("\n");
//2. 只有一个值,返回他本身
if(inl == inr) return new TreeNode(inorder[inl]);
//3. 如果不只一个,前序第一个是root
TreeNode root = new TreeNode(preorder[prel]);//不是0!!是preleft!!
//4. 找到root.val在中序中的位置(以左右子树结点个数分割前序)
int idx = 0;
for(int i=inl; i<=inr; i++) {
if(inorder[i] == root.val) {
idx = i;
break;
}
}
//5. 递归左子树:
// 前序起始位置变为prel+1,前序末尾位置变为(前序起始位置+前序个数-1)
// 中序起始位置不变,中序末尾位置变为rootindex-1
// 前序当前序列个数 = idx - inl
root.left = builder(preorder, prel+1, prel+idx-inl,
inorder, inl, idx-1);
//6. 递归右子树:
// 前序起始位置变为,前序起始位置变为(前序起始位置+前序个数),前序末尾位置不变prer
// 中序起始位置rootindex+1, 中序末尾位置不变
// 前序当前序列个数 = rootindex - inl
root.right = builder(preorder, prel+idx-inl+1, prer,
inorder, idx+1, inr);
//7. 返回root
return root;
}
654. 最大二叉树
https://leetcode-cn.com/problems/maximum-binary-tree/
public TreeNode constructMaximumBinaryTree(int[] nums) {
return bigtree(nums, 0, nums.length-1);
}
/**
*
* @param nums 数组
* @param idxl 左边界
* @param idxr 右边界
*/
public TreeNode bigtree(int[] nums, int idxl, int idxr) {
// 1. 空返回null
if(idxl > idxr) return null;
// 2. 只有一个直接返回
if(idxl == idxr) return new TreeNode(nums[idxl]);
// 3. 不止一个数,找到最大值他就是root
int ans = nums[idxl];
int idxroot = idxl;
for(int i=idxl+1; i<=idxr; i++){
if(nums[i] > ans){
ans = nums[i];
idxroot = i;
}
}
TreeNode root = new TreeNode(ans);
// 4. 递归左子树,左起点不变, 右终点idxroot-1
root.left = bigtree(nums, idxl, idxroot-1);
// 5. 递归右子树,左起点idxroot+1, 右终点不变
root.right = bigtree(nums, idxroot+1, idxr);
// 返回root
return root;
}