二叉树
104. 二叉树的最大深度
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
递归
class Solution {
public int maxDepth(TreeNode root) {
if(root==null){
return 0;
}
return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}
}
100. 相同的树
给你两棵二叉树的根节点 p
和 q
,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
递归
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null && q ==null){
return true;
}
if((p !=null && q ==null )|| (q!=null && p==null)){
return false;
}
return p.val==q.val && isSameTree(p.left, q.left ) && isSameTree(p.right, q.right);
}
}
226. 翻转二叉树
给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
递归
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root ==null){
return root;
}
TreeNode temp=root.left;
root.left=root.right;
root.right=temp;
invertTree(root.left);
invertTree(root.right);
return root;
}
}
101. 对称二叉树
给你一个二叉树的根节点 root
, 检查它是否轴对称。
递归
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root ==null){
return false;
}
return isSymmetric(root.left,root.right);
}
public boolean isSymmetric(TreeNode node1, TreeNode node2){
if(node1 ==null && node2 ==null){
return true;
}else if (node1 !=null && node2 !=null){
return node1.val ==node2.val && isSymmetric(node1.left, node2.right)
&& isSymmetric(node1.right, node2.left);
}else{
return false;
}
}
}
105. 从前序与中序遍历序列构造二叉 树
给定两个整数数组 preorder
和 inorder
,其中 preorder
是二叉树的先序遍历, inorder
是同一棵树的中序遍历,请构造二叉树并返回其根节点。
解法:递归,在中序遍历中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的,因此我们就可以对应到前序遍历的结果中,对上述形式中的所有左右括号进行定位。
同时使用hashMap来存储中序遍历的节点和位置。用来方便计算左右子树的长度。
class Solution {
private Map<Integer, Integer> indexMap;
public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
if (preorder_left > preorder_right) {
return null;
}
// 前序遍历中的第一个节点就是根节点
int preorder_root = preorder_left;
// 在中序遍历中定位根节点
int inorder_root = indexMap.get(preorder[preorder_root]);
// 先把根节点建立出来
TreeNode root = new TreeNode(preorder[preorder_root]);
// 得到左子树中的节点数目
int size_left_subtree = inorder_root - inorder_left;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
return root;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
// 构造哈希映射,帮助我们快速定位根节点
indexMap = new HashMap<Integer, Integer>();
for (int i = 0; i < n; i++) {
indexMap.put(inorder[i], i);
}
return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
}
}
106. 从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
解法,同样使用map来存储inorder的值和index。
因为postorder最后的元素就是根节点,所以可以直接length--得到。
class Solution {
int post_idx;
int[] inorder;
int[] postorder;
Map<Integer, Integer> idx_map = new HashMap<Integer, Integer>();
public TreeNode helper(int in_left, int in_right){
if(in_left > in_right){
return null;
}
int root_val=postorder[post_idx];
TreeNode root = new TreeNode(root_val);
int index = idx_map.get(root_val);
post_idx--;
//注意这里的顺序,因为我们是通过后续遍历的post_idx来定位root节点,后续遍历是先左,再右,最后后。所以这里的顺序得反过来,先右后左 。
root.right=helper(index+1, in_right);
root.left = helper(in_left,index-1);
return root;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.postorder=postorder;
this.inorder=inorder;
post_idx=inorder.length-1;
int idx=0;
for(Integer val: inorder){
idx_map.put(val, idx++);
}
return helper(0,inorder.length-1);
}
}
117. 填充每个节点的下一个右侧节点指针 II
给定一个二叉树:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL
。
初始状态下,所有 next 指针都被设置为 NULL
。
解法:层次遍历
class Solution {
public Node connect(Node root) {
if (root == null) {
return null;
}
Queue<Node> queue = new ArrayDeque<Node>();
queue.offer(root);
while (!queue.isEmpty()) {
int n = queue.size();
Node last = null;
for (int i = 1; i <= n; ++i) {
Node f = queue.poll();
if (f.left != null) {
queue.offer(f.left);
}
if (f.right != null) {
queue.offer(f.right);
}
if (i != 1) {
last.next = f;
}
//last是本层的第一个节点
last = f;
}
}
return root;
}
}
114. 二叉树展开为链表
给你二叉树的根结点 root
,请你将它展开为一个单链表:
- 展开后的单链表应该同样使用
TreeNode
,其中right
子指针指向链表中下一个结点,而左子指针始终为null
。 - 展开后的单链表应该与二叉树 先序遍历 顺序相同。
解法一,前序遍历
//递归法
class Solution {
public void flatten(TreeNode root) {
List<TreeNode> list = new ArrayList<TreeNode>();
preorderTraversal(root, list);
int size = list.size();
for (int i = 1; i < size; i++) {
TreeNode prev = list.get(i - 1), curr = list.get(i);
prev.left = null;
prev.right = curr;
}
}
public void preorderTraversal(TreeNode root, List<TreeNode> list) {
if (root != null) {
list.add(root);
preorderTraversal(root.left, list);
preorderTraversal(root.right, list);
}
}
}
迭代法
class Solution {
public void flatten(TreeNode root) {
List<TreeNode> list = new ArrayList<TreeNode>();
Deque<TreeNode> stack = new LinkedList<TreeNode>();
TreeNode node = root;
while (node != null || !stack.isEmpty()) {
while (node != null) {
list.add(node);
stack.push(node);
node = node.left;
}
node = stack.pop();
node = node.right;
}
int size = list.size();
for (int i = 1; i < size; i++) {
TreeNode prev = list.get(i - 1), curr = list.get(i);
prev.left = null;
prev.right = curr;
}
}
}
解法2:
- 将左子树插入到右子树的地方
- 将原来的右子树接到左子树的最右边节点
- 考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null
public void flatten(TreeNode root) {
while (root != null) {
//左子树为 null,直接考虑下一个节点
if (root.left == null) {
root = root.right;
} else {
// 找左子树最右边的节点
TreeNode pre = root.left;
while (pre.right != null) {
pre = pre.right;
}
//将原来的右子树接到左子树的最右边节点
pre.right = root.right;
// 将左子树插入到右子树的地 方
root.right = root.left;
root.left = null;
// 考虑下一个节点
root = root.right;
}
}
}
112. 路径总和
给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。
叶子节点 是指没有子节点的节点
递归,如果是叶子结点,则判断值是否一致,否则左右继续递归。
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null){
return false;
}
if(root.left==null && root.right==null){
return root.val ==targetSum;
}
return hasPathSum(root.left,targetSum-root.val) || hasPathSum(root.right,targetSum-root.val);
}
}