学习二叉树
follow:代码随想录
112. 路经之和
题目描述:
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum。如果存在,返回 true;否则,返回 false 。
解答:
递归法:
返回值和参数值:返回值是boolean,参数值是根节点+目标值
本题属于搜索二叉树其中一条符合条件的路径,所以递归函数需要返回值
终止条件:节点为空的时候(或者是遍历到了叶节点+没有达到目标值);或者遍历到了叶节点+达到了目标值
单次逻辑:以左右节点为根节点,再次递归
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
//采用前序遍历 + 回溯
if(root == null) return false;
if(root.left == null && root.right == null && root.val == targetSum) return true;
//节点上的数不一定是正数
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}
}
迭代法:
public boolean hasPathSum(TreeNode root, int targetSum) {
Deque<TreeNode> stack = new LinkedList<>();
//前序遍历
int sum = 0;
if(root == null) return false;
stack.addFirst(root);
while(!stack.isEmpty()){
TreeNode node = stack.peekFirst();
if(node != null){
sum += node.val;
if(node.left == null && node.right == null && sum == targetSum){
return true;
}
//利用null来标志该节点是否被遍历
stack.addFirst(null);
if(node.right != null) stack.addFirst(node.right);
if(node.left != null) stack.addFirst(node.left);
}else{
stack.removeFirst();
node = stack.removeFirst();
sum -= node.val;
}
}
return false;
}
113. 路经总和2⃣️
题目描述:
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
解答:
递归法:这里输入遍历整棵树,递归函数不需要返回值
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<Integer> path = new ArrayList<>();
countPath(root, targetSum, path);
return res;
}
public void countPath(TreeNode root, int targetSum, List<Integer> path){
if(root == null) return;
if(root.left == null && root.right == null && root.val == targetSum){
path.add(root.val);
//注意:这里要新建一个arraylist,因为这里是地址传递,后续的path的回溯会改变res中的值
res.add(new ArrayList<>(path));
path.remove(path.size() - 1);
return;
}
path.add(root.val);
if(root.left != null){
countPath(root.left, targetSum - root.val, path);
}
if(root.right != null){
countPath(root.right, targetSum - root.val, path);
}
//回溯
path.remove(path.size() - 1);
}
}
迭代法:
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
Deque<TreeNode> stack = new LinkedList<>();
if(root != null) stack.addFirst(root);
int sum = 0;
while(!stack.isEmpty()){
TreeNode node = stack.peekFirst();
if(node != null){
sum += node.val;
path.add(node.val);
if(sum == targetSum && node.left == null && node.right == null){
res.add(new ArrayList<>(path));
}
stack.addFirst(null);
if(node.left != null) stack.addFirst(node.left);
if(node.right != null) stack.addFirst(node.right);
}else{
//回溯
stack.removeFirst();
node = stack.removeFirst();
path.remove(path.size() - 1);
sum -= node.val;
}
}
return res;
}
105 从前序与中序遍历序列构造二叉树
教程:教程链接
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildSubTree(preorder, 0, preorder.length, inorder, 0 ,inorder.length);
}
public TreeNode buildSubTree(int[] preorder, int preleft, int preright, int[] inorder, int inleft, int inright){
if(inright - inleft == 1) return new TreeNode(inorder[inleft]);
if(inright - inleft < 1) return null;
TreeNode root = new TreeNode(preorder[preleft]);
//找切割点
int delimiterindex = 0;
for(delimiterindex = inleft; delimiterindex < inright; delimiterindex++){
if(inorder[delimiterindex] == preorder[preleft]) break;
}
root.left = buildSubTree(preorder, preleft + 1, preleft + delimiterindex - inleft, inorder, inleft, delimiterindex);
root.right = buildSubTree(preorder, preleft + delimiterindex - inleft + 1, preright, inorder, delimiterindex + 1, inright);
return root;
}
}
106 从中序与后序遍历序列构造二叉树
题目描述:
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return buildSubTree(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
public TreeNode buildSubTree(int[] inorder, int inleft, int inright, int[] postorder, int postleft, int postright){
if(inright - inleft == 1) return new TreeNode(inorder[inleft]);
if(inright - inleft < 1) return null;
TreeNode root = new TreeNode();
//找到切割点
root.val = postorder[postright - 1];
int delimiterindex = 0;
for(delimiterindex = inleft; delimiterindex < inorder.length; delimiterindex++){
if(inorder[delimiterindex] == root.val){
break;
}
}
//划分子节点 左闭右开
root.left = buildSubTree(inorder, inleft, delimiterindex, postorder, postleft, postleft + delimiterindex - inleft);
root.right = buildSubTree(inorder, delimiterindex + 1, inright, postorder, postleft + delimiterindex - inleft, postright - 1);
return root;
}
}
654 最大二叉树
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
public TreeNode constructMaximumBinaryTree(int[] nums) {
return maximumBinaryTree(nums, 0, nums.length);
}
//采用递归的方法,传入的参数是相当于切割后的数组
public TreeNode maximumBinaryTree(int[] nums, int left, int right){
//该种情况是一侧只有一个元素,则不用再次遍历
if(right - left == 1) return new TreeNode(nums[left]);
//某一侧没有元素
if(right - left < 1) return null;
int max_index = sort(nums, left, right);
TreeNode root = new TreeNode(nums[max_index]);
//前序遍历 分别找到左右节点
root.left = maximumBinaryTree(nums, left, max_index);
root.right = maximumBinaryTree(nums, max_index + 1, right);
return root;
}
public int sort(int[] nums, int left, int right){
int temp = 0;
int record = -1;
for(int i = left; i < right; i++){
if(nums[i] > record)
{
temp = i;
record = nums[i];
}
}
return temp;
}