代码随想录——二叉树(二):对称,平衡,遍历路径,二叉树最左(最右同理),构造二叉树

题目来自:https://www.programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html#%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E7%A7%8D%E7%B1%BB

1. 对称二叉树

101. 对称二叉树

  1. 递归
  2. 迭代
	/*
	 * 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. 另一棵树的子树

这题下线很低,上限很高

  1. 遍历每一个结点,每一个结点判断是否相等
  2. kmp算法
  3. 构造哈希,埃氏筛。不是给人做的

2. 平衡二叉树

110. 平衡二叉树

https://leetcode-cn.com/problems/balanced-binary-tree/

  1. 递归(如果不平衡就是-1)
  2. 迭代,没写
    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;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平什么阿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值