二叉树一种具有天然递归结构的树 ,一种非线性结构
满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树,最后一层是满的
完全二叉树:如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布
平衡二叉树:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1
二叉搜索树:又叫二叉排序树,二叉查找树,每个节点的值都大于其左子树的所有节点的值,小于其右子树的所有节点的值
哈希表失去了数据的顺序性
- leetcode144:二叉树的前序遍历
顺序:访问根节点->前序遍历左子树->前序遍历右子树
void preorder( Treenode * node){
if (node) { // 如果节点不为空
count << node->val; // 打印这个节点的值
preorder ( node ->left); //左子树
preorder ( node -> right); //右子树
}
}
2.leetcode 104:给定一个二叉树,找出其最大深度
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数
示例:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7 //返回其深度为3
实现了两种做法,都是dfs,一种是递归,一种是借助栈
递归实现:解决递归问题的思路通常都是将一个大的问题递推分解为几个很容易解决的情况,再将这些情况加在一起,就是我们需要的答案,比如说,在这题里,我们需要求的是层数,然后一棵二叉树可以分解为许许多多个左树和右数,我们就通过递归,每递归找到一层,就加上1。
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
else:
left_height = self.maxDepth(root.left)
right_height = self.maxDepth(root.right)
return max(left_height, right_height) + 1
//1 代表根节点
使用栈来辅助实现dfs: //时间复杂度O(n)
//空间复杂度:线性表最差O(n)、二叉树完全平衡最好O(lo
class Solution:
def maxDepth(self, root):
stack = []
if root!=None:
stack.append((1, root))
depth = 0 //DFS实现前序遍历,每个节点记录其所在深度
while stack!=[]:
currDepth, root = stack.pop() //记录当前节点所在深度
if root!=None:
depth = max(currDepth, depth) //DFS过程不断比较更新最大深度
stack.append((currDepth+1, root.left))//当前节点的子节点入栈,同时深度+1
stack.append((currDepth+1, root.right))
return depth
3.leetcode 111:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最小深度2
1.递归思路:先判断是否root为空,左右子树为空,如果左右子树一边为空,只需要调用另一边子树,如果都不为空,判断两边的最小值再加1
public int minDepth(TreeNode root) {
if(root==null) return 0;
if(root.left==null) return 1+minDepth(root.right);
if(root.right==null) return 1+minDepth(root.left);
int minleft=minDepth(root.left);
int minright=minDepth(root.right);
return 1+Math.min(minleft,minright);
}
2.借助栈迭代实现:
class Solution:
def minDepth(self, root):
result = float('inf')
if not root:
return 0
q= [(root, 1)]
while stack:
node, depth = q.pop(0)
if not node.left and not node.right:# 叶子节点
result = min(result, depth)
if node.left:
q.append((node.left, depth + 1))
if node.right:
q.append((node.right, depth + 1))
return result
4.leetcode 226:反转一颗二叉树
示例:输入:
4
/ \
2 7
/ \ / \
1 3 6 9
输出:
4
/ \
7 2
/ \ / \
9 6 3 1
算法:运用二叉树的广度遍历,将每个节点的左子节点和右子节点调换
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
TreeNode temp = root.left;
root.left = invertTree(root.right);
root.right = invertTree(temp);
invertTree(root.left);
invertTree(root.right);
return root;
}
}
5.leetcode 100:same tree
给定两个二叉树,编写一个函数来检验它们是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: 1 1
/ \ / \
2 3 2 3
[1,2,3], [1,2,3]
输出: true
示例 2:
输入: 1 1
/ \
2 2
[1,2], [1,null,2]
输出: false
思路:1.当两个结点都为null的时候,表示结点相等
2.当两个结点都不为null
1.结点的值相等,表示当前结点相等, 再判断当前结点的子节点是否相等
2.结点的值不相等,返回false
3.只有一个结点为null, 两个结点一定不想等,返回false
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(q == NULL && p == NULL) return true;
if(q != NULL && p!= NULL){
if(q->val != p->val) return false;
else return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
} else return false;
}
};
6.leetcode 101:给定一个二叉树,检查它是否是镜像对称的。
class Solution:
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
if not root:
return True
return self.helper(root.left, root.right)
def helper(self, left, right):
if left == None and right == None:
return True
elif left == None or right == None:
return False
elif left.val != right.val:
return False
else:
return self.helper(left.left, right.right) and self.helper(left.right, right.left)
7.leetcode 222:给定一棵完全二叉树,求完全二叉树的节点个数
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,
并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
思路:由 root 根结点往下,分别找最靠左边和最靠右边的路径长度,如果长度相等,则证明二叉树最后一层节点是满的,是满二叉树,
直接返回节点个数,如果不相等,则节点个数为左子树的节点个数加上右子树的节点个数再加1(根节点),
其中左右子树节点个数的计算可以使用递归来计算:
class Solution {
public:
int countNodes(TreeNode* root) {
if(!root) return 0;
TreeNode* left=root,*right=root;
int leftCou=0,rightCou=0;
while(left){
leftCou++;
left=left->left;
}
while(right){
rightCou++;
right=right->right;
}
if(leftCou==rightCou) return pow(2,leftCou)-1; //leftcou代表层数
return countNodes(root->left)+countNodes(root->right)+1;
}
};
8.leetcode 110: 给定一个二叉树,判断它是否是高度平衡的二叉树。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。
思路:求二叉树高度,可以考虑递归深度遍历求解,再考虑本题要求,
发现在深度遍历的同时,可以顺便判断每个结点是否满足其左右子树的高度差的绝对值是否小于等于1,
所以,我们可以用一个全局布尔变量来表示该二叉树是否为平衡二叉树,然后在递归遍历时,
对每个结点进行判断,一旦不满足,就把全局布尔变量置为false,最后在主函数中返回该布尔变量即可。
class Solution {
public:
bool isBalanced(TreeNode* root) {
height(root);
return is_balance;
}
private:
bool is_balance = 1; //全局布尔变量
int height(TreeNode *p){
if(p != NULL){
int lh = height(p->left), rh = height(p->right); //递归求解结点p的左右子树高度
if(abs(lh - rh) > 1)
is_balance = 0; //高度差绝对值大于1,将is_balance置为false
return max(lh, rh)+1; //返回以该结点为根结点的树的高度
}
else
return 0; //如果为结点为空,返回高度0
}
};
9. leetcode 112:路径总和:给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
class Solution:
def hasPathSum(self, root, sum):
if root is None:
return False
if sum == root.val and root.left is None and root.right is None:
return True //叶子节点
return self.hasPathSum(root.left, sum-root.val) or self.hasPathSum(root.right, sum-root.val)
10.leetcode 404:给定一个二叉树,求其所有左叶子的和,使用递归,若当前节点的左节点是叶子,把当前节点的左节点的值加入和中,否则对其左右节点进行递归。
public int sumOfLeftLeaves(TreeNode root) {
if(root == null)
return 0;
int sum = 0;
if(root.left != null && root.left.left == null && root.left.right == null)
sum += root.left.val;
return sum + sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}
11.leetcode 257:给定一个二叉树,返回所有从根节点到叶子节点的路径。
输入:
1
/ \
2 3
\
5
输出: ["1->2->5", "1->3"]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> list=new LinkedList<String>();
helper(root,list,new String());
return list;
}
public void helper(TreeNode root,List<String>list,String s){
if(root==null) //root为空,易知,只有一种情况,那就是题目所给是空树。
return;
if(root.left==null&&root.right==null){ //没有左右孩子,当前节点是叶子节点,所以形成一条路径=s(根节点到父节点路径)+当前节点
list.add(s+root.val);
return ;
}
if(root.left!=null)
helper(root.left,list,s+root.val+"->"); //存在左孩子,所以到当前节点路径=s(根节点到父节点路径)+当前节点值+"->"
if(root.right!=null)
helper(root.right,list,s+root.val+"->"); //同理
}
}
12.leetcode 113:路径总和 II
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
class Solution:
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: List[List[int]]
"""
result = list()
if root == None:
return result
if not root.left and not root.right and sum == root.val:
result.append([root.val])
return result
left = self.pathSum(root.left, sum - root.val)
for i in left:
i.insert(0, root.val)
result.append(i)
right = self.pathSum(root.right, sum - root.val)
for i in right:
i.insert(0, root.val)
result.append(i)
return result
13.leetcode 129:
给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。
例如,从根到叶子节点路径 1->2->3 代表数字 123。
计算从根到叶子节点生成的所有数字之和。
说明: 叶子节点是指没有子节点的节点。
示例 1:
输入: [1,2,3]
1
/ \
2 3
输出: 25
解释:
从根到叶子节点路径 1->2 代表数字 12.
从根到叶子节点路径 1->3 代表数字 13.
因此,数字总和 = 12 + 13 = 25.
示例 2:
输入: [4,9,0,5,1]
4
/ \
9 0
/ \
5 1
输出: 1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495.
从根到叶子节点路径 4->9->1 代表数字 491.
从根到叶子节点路径 4->0 代表数字 40.
因此,数字总和 = 495 + 491 + 40 = 1026.
14.leetcode 437:路径总和 III
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
返回 3。和等于 8 的路径有:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
15.leetcode 235:问题描述:给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。最近公共祖先的定义为:对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
16.leetcode 17:
17.leetcode 93:
18.leetcode 131:
19.leetcode 46:
20.leetcode 75:
21.leetcode 88:
22.leetcode 167:
23.leetcode 215:
24.leetcode 125:
25.leetcode 344:
26.leetcode 11:
27.leetcode 209:
28.leetcode 3:
29.leetcode 438:
30.leetcode 76:
31.leetcode 349:
32.leetcode 350:
33.leetcode