文章目录
2、树(简单篇2)
2.1、965. 单值二叉树
如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。
只有给定的树是单值二叉树时,才返回 true;否则返回 false。
示例 1:
输入:[1,1,1,1,1,null,1] 输出:true 示例 2:
输入:[2,2,2,5,2] 输出:false
提示:
给定树的节点数范围是 [1, 100]。 每个节点的值都是整数,范围为 [0, 99] 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/univalued-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:题意不难理解,判断一棵二叉树的结点值是否唯一,是就返回true,否则返回false。
提示还给出了节点数的范围,至少有一个结点。
如果是一个数组,判断值是否唯一,很简单,遍历一遍数组就行了,如果发现有与第一个元素值不同的就返回false,否则返回true。
现在问题是数组变成二叉树,二叉树也是有遍历的啊,前中后,任君选择。
简单的框架:
bool tag = true;
void isUniqueTree(TreeNode* root,int val,bool &tag){
if(root==NULL||tag==false) return;//树为空或tag为false,就没必要遍历了
if(root->val!=val) {tag=false;return;}//发现一个不等的值,置tag为false
isUniqueTree(root->left,val,tag);
isUniqueTree(root->right,val,tag);
}
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isUnivalTree(TreeNode* root) {
bool tag = true;
isUnivalTreeHelper(root,root->val,tag);
return tag;
}
void isUnivalTreeHelper(TreeNode* root,int val,bool &tag){
if(root==NULL||tag==false) return ;
if(root->val!=val) {tag = false;return;}
isUnivalTreeHelper(root->left,val,tag);
isUnivalTreeHelper(root->right,val,tag);
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private boolean isUnivalTreeHelper(TreeNode root,int val){
//Java 与 C++ 有区别
if(root==null) return true;
if(root.val!=val) return false;
else return isUnivalTreeHelper(root.left,val) && isUnivalTreeHelper(root.right,val);
}
public boolean isUnivalTree(TreeNode root) {
return isUnivalTreeHelper(root,root.val);
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isUnivalTree(self, root: TreeNode) -> bool:
return self.preOrderHelper(root,root.val)
def preOrderHelper(self,root:TreeNode,val:int)->bool:
if root is None:
return True
else:
if root.val== val:
return self.preOrderHelper(root.left,val) and self.preOrderHelper(root.right,val)
else:
return False
2.1、669. 修剪二叉搜索树
给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L)
。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。示例 1:
输入:
L = 1 R = 2输出:
示例 2:输入:
L = 1 R = 3输出:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trim-a-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:修剪二叉搜索树,又是二叉搜索树,莫名其妙想到中序遍历…
修剪就相当于增删查改的删吧,换个问题:如果是一个数组,只保留给定范围[L,R]的元素,很简单就想到遍历了是吧,换成二叉搜索树的话同样也是这样,没什么难度的。
简单框架:
void traversal(TreeNode* root){
if(root==NULL) return;
traversal(root->left);
//判断是否删除删除
traversal(root->right);
}
事实真的这么简单吗?其实并不是的,树的删除(就地修改)一定要谨慎,因为它并不像是数组那样的连续结构,树的删除如果出错,就是一整个结构的破坏,最常见就是丢失指针的问题,很容易失去一些数据,从而引起整个程序崩溃。
就如上面的代码,一旦root被删除了,那么traversal(root->right) 就会抛出异常,root都为空了,哪还有右孩子,所以树的删除(就地修改)一定要谨慎!
上面举了个错误的想法,下面再来谈谈如何分析:
先看一棵常见的二叉搜索树,这么一看觉得是有点复杂,毕竟有12个结点。我们来简化一下:
简化成一个根节点,还有A、B两棵子树,那么问题来了:修剪以root为根结点的树,是不是相当于先修剪A子树,再修剪B子树,再看看根结点是否需要修剪,把一件事情细分成三个小任务,逐一击破。
那么修剪A子树和修剪B子树,是不是相当于调用本身的函数,就是用递归了嘛!两个小任务完成。
根结点是否需要修剪,如果不需要修剪,那么只需要修剪A、B子树就完成了。如果需要修剪,那么该保留A子树的修剪结果呢?还是保留B子树的修剪结果呢?
等等,有没有发现先做根结点的判断效率更高?既然根结点是要被修剪的,那么只需要保留一边的子树就行,那就没必要先修剪了子树再判断要保留的子树。
简单的框架:
TreeNode* trimBST(TreeNode* root,int L,int R){
if(root==NULL) return NULL;
if(root->val<L) return trimBST(root->right,L,R);//根节点需要被修剪,并在值还在[L,R]的左边,自然要返回右子树的修剪结果了
else if(root->val>R) return trimBST(root->left,L,R);//根节点需要被修剪,并在值还在[L,R]的右边,自然要返回左子树的修剪结果了
else {//既然根节点的值在[L,R]内,那么就去修剪左右子树吧
root->left = trimBST(root->left,L,R);
root->right = trimBST(root->right,L,R);
return root;
}
}
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int L, int R) {
if(root==NULL) return NULL;
if(root->val<L) return trimBST(root->right,L,R);
else if(root->val>R) return trimBST(root->left,L,R);
else{
root->left = trimBST(root->left,L,R);
root->right = trimBST(root->right,L,R);
return root;
}
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode trimBST(TreeNode root, int L, int R) {
if(root==null) return null;
if(root.val<L) return trimBST(root.right,L,R);
else if (root.val>R) return trimBST(root.left,L,R);
else{
root.left = trimBST(root.left,L,R);
root.right = trimBST(root.right,L,R);
return root;
}
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def trimBST(self, root: TreeNode, L: int, R: int) -> TreeNode:
if root is None:
return None
if root.val <L:
return self.trimBST(root.right,L,R)
elif root.val>R:
return self.trimBST(root.left,L,R)
else:
root.left=self.trimBST(root.left,L,R)
root.right=self.trimBST(root.right,L,R)
return root
2.3、102. 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例: 二叉树:[3,9,20,null,null,15,7],
3 / \ 9 20 / \ 15 7 返回其层次遍历结果: [ [3], [9,20], [15,7] ]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:现在碰到另一种遍历方式:层次遍历,之前的前中后遍历方式都是属于深度优先,而层次遍历是属于广度优先。
层次遍历就是把树的一层层分开遍历,每一层从左到右进行遍历,从例子不难看出。
层次遍历的实现最简单就是教科书上的使用辅助的队列,队列有个特性就是先进先出(FIFO)。
首先把根节点加入到队列中去,这是第一层遍历的开始,
遍历的过程就是:从队列中取出一个元素,并把它的左右孩子(如果有)加入到队列中。
现在这样是第二层遍历的开始,还是取队列的元素,还是和刚刚的步骤一样,这样一直到队列没有元素为止,层次遍历也就结束了。
简单框架:
void traversal(TreeNode* root){
queue;
queue.push(root);
while(!queue.empty()){
element = queue.pop()
visit(element)
queue.push(element->left)//如果有左孩子
queue.push(element->left)//如果有右孩子
}
题目要求返回的是二维数组,同一层的结点值在同一数组,所以实现上需要一点小修改。
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if(root!=NULL) q.push(root);
while(!q.empty()){
int count = q.size();
vector<int> v;
while(count){
TreeNode* element = q.front();
q.pop();
v.push_back(element->val);
if(element->left!=NULL) q.push(element->left);
if(element->right!=NULL) q.push(element->right);
count--;
}
res.push_back(v);
}
return res;
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
Queue<TreeNode> q = new LinkedList<TreeNode>();
if (root!=null) q.offer(root);
while(!q.isEmpty()){
List<Integer> v = new ArrayList<Integer>();
int count = q.size();
while(count>0){
TreeNode element = q.poll();
v.add(element.val);
if(element.left!=null) q.offer(element.left);
if(element.right!=null) q.offer(element.right);
count--;
}
res.add(v);
}
return res;
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
res = []
queue = []
if root is not None:
queue.append(root)
while(len(queue)>0):
count = len(queue)
v = []
while count>0:
element = queue.pop(0)
v.append(element.val)
if element.left is not None:
queue.append(element.left)
if element.right is not None:
queue.append(element.right)
count-=1
res.append(v)
return res
2.4、107. 二叉树的层次遍历 II
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如: 给定二叉树 [3,9,20,null,null,15,7],
3 / \ 9 20 / \ 15 7
返回其自底向上的层次遍历为:
[ [15,7], [9,20], [3] ]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:和上面的一样,只不过输出结果倒着输出而已。
直接贴代码。
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if(root!=NULL) q.push(root);
while(!q.empty()){
int count = q.size();
vector<int> v;
while(count){
TreeNode* element = q.front();
q.pop();
v.push_back(element->val);
if(element->left!=NULL) q.push(element->left);
if(element->right!=NULL) q.push(element->right);
count--;
}
res.push_back(v);
}
reverse(res.begin(),res.end());
return res;
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
Queue<TreeNode> q = new LinkedList<TreeNode>();
if (root!=null) q.offer(root);
while(!q.isEmpty()){
List<Integer> v = new ArrayList<Integer>();
int count = q.size();
while(count>0){
TreeNode element = q.poll();
v.add(element.val);
if(element.left!=null) q.offer(element.left);
if(element.right!=null) q.offer(element.right);
count--;
}
res.add(v);
}
Collections.reverse(res);
return res;
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
res = []
queue = []
if root is not None:
queue.append(root)
while(len(queue)>0):
count = len(queue)
v = []
while count>0:
element = queue.pop(0)
v.append(element.val)
if element.left is not None:
queue.append(element.left)
if element.right is not None:
queue.append(element.right)
count-=1
res.append(v)
res.reverse()
return res
2.5、637. 二叉树的层平均值
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组.
示例 1:
输入:
输出: [3, 14.5, 11]
解释: 第0层的平均值是 3, 第1层是 14.5, 第2层是 11. 因此返回 [3, 14.5, 11].
注意:节点值的范围在32位有符号整数范围内。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/average-of-levels-in-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:一连三题都是同一个框架:层次遍历,有了层次遍历的结果,求平均值还不是手到擒来。直接贴代码。不过要看题目有个注意!!!
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if(root!=NULL) q.push(root);
while(!q.empty()){
int count = q.size();
vector<int> v;
while(count){
TreeNode* element = q.front();
q.pop();
v.push_back(element->val);
if(element->left!=NULL) q.push(element->left);
if(element->right!=NULL) q.push(element->right);
count--;
}
res.push_back(v);
}
vector<double> mean;
for(int i=0;i<res.size();i++){
long temp = 0L;//要注意溢出问题
for(int j=0;j<res[i].size();j++){
temp += res[i][j];
}
mean.push_back((double)temp/res[i].size());
}
return mean;
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
Queue<TreeNode> q = new LinkedList<TreeNode>();
if (root!=null) q.offer(root);
while(!q.isEmpty()){
List<Integer> v = new ArrayList<Integer>();
int count = q.size();
while(count>0){
TreeNode element = q.poll();
v.add(element.val);
if(element.left!=null) q.offer(element.left);
if(element.right!=null) q.offer(element.right);
count--;
}
res.add(v);
}
List<Double> mean = new ArrayList<Double>();
for(int i=0;i<res.size();i++){
long temp =0;
for(int j=0;j<res.get(i).size();j++){
temp+=res.get(i).get(j);
}
mean.add((double)temp/res.get(i).size());
}
return mean;
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def averageOfLevels(self, root: TreeNode) -> List[float]:
res = []
queue = []
if root is not None:
queue.append(root)
while(len(queue)>0):
count = len(queue)
v = []
while count>0:
element = queue.pop(0)
v.append(element.val)
if element.left is not None:
queue.append(element.left)
if element.right is not None:
queue.append(element.right)
count-=1
res.append(v)
m = [mean(v) for v in res] #一个列表推导式搞定收工,人生苦短,我用Python
return m
2.6、257. 二叉树的所有路径
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
输入:
输出: [“1->2->5”, “1->3”]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/binary-tree-paths
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:仔细想想,从例子出发,从根结点到叶子结点的路径有两条,如果把这两条路径都走完,是不是相当于遍历了一遍二叉树?
那好,我们可以用遍历树的框架来试试能不能完成。
如果使用先中后遍历方式,那就是深度优先,第一次找到叶子结点的时候,其实已经走了一条路径了,例如先序遍历找到叶子节点5的时候,就已经形成了一条”1->2->5"的路径了。在访问每个结点的时候,需要记录父节点的路径,然后当前结点的值加入到路径中。
所以本题就是树的遍历的应用题。
简单框架:
void traversal(TreeNode* root,string pre_path){
//pre_path是父节点的路径
if(root==NULL) return ;
string cur_path = pre_path + root->val;
if(root->left==NULL && root->right==NULL){//已经是叶子结点
result.append(cur_path);//加入到结果集合中
}
traversal(root->left,cur_path);//遍历子树的时候,把当前路径传参
traversal(root->right,cur_path);
}
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> res;
if(root == NULL) return res;
string pre="";
binaryTreePathsHelper(root,res,pre);
return res;
}
void binaryTreePathsHelper(TreeNode* root,vector<string> &res,string pre){
if(root==NULL) return;
pre = pre + to_string(root->val)+"->";
if(root->left==NULL && root->right==NULL){
res.push_back(pre.substr(0,pre.size()-2));
}
binaryTreePathsHelper(root->left,res,pre);
binaryTreePathsHelper(root->right,res,pre);
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private void binaryTreePathsHelper(TreeNode root,String pre,List<String> res){
if(root==null) return;
String cur = pre+String.valueOf(root.val)+"->";
if(root.left==null&&root.right==null){
res.add(cur.substring(0,cur.length()-2));
}
binaryTreePathsHelper(root.left,cur,res);
binaryTreePathsHelper(root.right,cur,res);
}
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<String>();
binaryTreePathsHelper(root,"",res);
return res;
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def binaryTreePathsHelper(self,root:TreeNode,pre:str,res:List[str]):
if root is None:
return None;
cur = pre+str(root.val)+"->"
if root.left == None and root.right==None:
res.append(cur[:-2])
self.binaryTreePathsHelper(root.left,cur,res)
self.binaryTreePathsHelper(root.right,cur,res)
def binaryTreePaths(self, root: TreeNode) -> List[str]:
res = []
self.binaryTreePathsHelper(root,"",res)
return res
2.7、235. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x
的深度尽可能大(一个节点也可以是它自己的祖先)。”例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2和节点 8 的最近公共祖先是 6。
示例 2: 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p =2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。说明: 所有节点的值都是唯一的。 p、q 为不同节点且均存在于给定的二叉搜索树中。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:
在说明中有提到,结点值唯一,并且p、q不同结点,肯定存在与二叉搜索树中,所以不用管查找失败的问题。
情况1:要找的两个结点分别在根节点的两侧,那么很显然,最近公共祖先就是根节点。
情况2:如果要找的两个结点都在根节点的同一侧,那么肯定是要从子树重新开始,如上图则需要在以2为根节点的树中继续查找。
很显然,开始递归了。
情况3:如果根节点就是要找的元素呢,显然根节点就是最近公共祖先。
简单理理:
1、如果根节点是要查找的结点,那么最近公共祖先就是根节点。
2、如果要找的结点在根节点两侧,则根节点就是最近公共祖先。
3、如果要找的结点在根节点同一侧,则递归查找子树。
这么理理,算法就出来了。直接上代码吧。
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==NULL||p==NULL||q==NULL) return NULL;//判空
if(root->val==p->val || root->val==q->val) return root;//如果根节点的值等于给出的两个值,则根节点就是最近公共祖先
//看是同在左侧或右侧
if(root->val>p->val && root->val>q->val) return lowestCommonAncestor(root->left,p,q);
if(root->val<p->val && root->val<q->val) return lowestCommonAncestor(root->right,p,q);
else return root;//不同侧就返回根节点
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null||p==null||q==null) return null;
if(root.val==p.val || root.val==q.val) return root;
if(root.val>p.val && root.val>q.val) return lowestCommonAncestor(root.left,p,q);
if(root.val<p.val && root.val<q.val) return lowestCommonAncestor(root.right,p,q);
else return root;
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root is None or p is None or q is None:
return None
if root.val==p.val or root.val == q.val:
return root
if root.val>p.val and root.val> q.val:
return self.lowestCommonAncestor(root.left,p,q)
if root.val<p.val and root.val <q.val:
return self.lowestCommonAncestor(root.right,p,q)
else:
return root
2.8、872. 叶子相似的树
请考虑一颗二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。
举个例子,如上图所示,给定一颗叶值序列为 (6, 7, 4, 9, 8) 的树。
如果有两颗二叉树的叶值序列是相同,那么我们就认为它们是 叶相似 的。
如果给定的两个头结点分别为 root1 和 root2 的树是叶相似的,则返回 true;否则返回 false 。
提示:
给定的两颗树可能会有 1 到 200 个结点。 给定的两颗树上的值介于 0 到 200 之间。来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/leaf-similar-trees
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:实际上是要求出叶子序列,然后比较两棵树的叶子序列是否相等的问题。一个遍历就可以求出叶子序列了,实际上还是遍历的应用。
简单框架:
vector<int> getLeafList(TreeNode* root); //遍历树的函数
bool leafSimilar(TreeNode* root1,TreeNode* root2){
leafList1 = getLeafList(root1)
leafList2 = getLeafList(root2)
if(leafList1 == leafList2) return true;
else return false;
}
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void traversal(TreeNode* root,vector<int> &res){
if(root==NULL) return;
if(root->left==NULL && root->right==NULL) res.push_back(root->val);
traversal(root->left,res);
traversal(root->right,res);
}
vector<int> getLeaf(TreeNode* root){
vector<int> res;
traversal(root,res);
return res;
}
bool leafSimilar(TreeNode* root1, TreeNode* root2) {
vector<int> v1 = getLeaf(root1);
vector<int> v2 = getLeaf(root2);
return v1==v2;
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public void traversal(TreeNode root,List<Integer> res){
if(root==null) return;
if(root.left==null && root.right==null) res.add(root.val);
traversal(root.left,res);
traversal(root.right,res);
}
public boolean leafSimilar(TreeNode root1, TreeNode root2) {
List<Integer> v1 = new ArrayList<Integer>();
List<Integer> v2 = new ArrayList<Integer>();
traversal(root1,v1);
traversal(root2,v2);
return v1.equals(v2);
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def traversal(self,root: TreeNode,res:List[int]):
if root is None:
return None
if root.left is None and root.right is None:
res.append(root.val)
self.traversal(root.left,res)
self.traversal(root.right,res)
def leafSimilar(self, root1: TreeNode, root2: TreeNode) -> bool:
v1,v2 = [],[]
self.traversal(root1,v1)
self.traversal(root2,v2)
return v1==v2
2.9、1022. 从根到叶的二进制数之和
给出一棵二叉树,其上每个结点的值都是 0 或 1 。每一条从根到叶的路径都代表一个从最高有效位开始的二进制数。例如,如果路径为 0 -> 1
-> 1 -> 0 -> 1,那么它表示二进制数 01101,也就是 13 。
对树上的每一片叶子,我们都要找出从根到该叶子的路径所表示的数字。
以 10^9 + 7 为模,返回这些数字之和。
示例:
输入:[1,0,1,0,1,0,1] 输出:22
解释:(100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22
提示:
树中的结点数介于 1 和 1000 之间。 node.val 为 0 或 1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-root-to-leaf-binary-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:本题和【2.6、257. 二叉树的所有路径】是类似的,都是同一个套路,只不过本题的值是组成一个二进制串,然后转换为十进制的数字,并且 以 109 + 7 为模,提示中有说到,节点数至多1000个,长达1000位的二进制数转为数字,肯定有溢出问题,所以答案要返回以 109 + 7 为模的结果。
(力扣很多题解上并没有注意这个问题,即使直接把结果都加到一个int变量上也没有溢出,可能是题目描述有问题。)
模运算与基本四则运算有些相似
- (a + b) % p = (a % p + b % p) % p (1)
- (a - b) % p = (a % p - b % p) %p (2)
- (a * b) % p = (a % p * b % p) % p (3)
- a ^ b % p = ((a % p)^b) %p (4)
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* root,int &sum,int pre)
{
if(root==NULL) return;
pre = pre*2+root->val;
if(root->left==NULL&&root->right==NULL)
sum+=pre;
dfs(root->left,sum,pre);
dfs(root->right,sum,pre);
}
int sumRootToLeaf(TreeNode* root) {
int sum=0;
dfs(root,sum,0);
return sum%1000000007;
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int sum = 0;
public void dfs(TreeNode root,int pre){
if(root==null) return;
pre=pre*2+root.val;
if(root.left==null && root.right==null)
this.sum+=pre;
dfs(root.left,pre);
dfs(root.right,pre);
}
public int sumRootToLeaf(TreeNode root) {
this.sum = 0;
dfs(root,0);
return this.sum%1000000007;
}
}
题解代码(Python):(Python int类型长度无限,不需要担心溢出问题)
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.total = 0
def dfs(self,root:TreeNode,count:int) -> int:
if root is None:
return None
count = count*2 + root.val
if root.left is None and root.right is None:
self.total += count
self.dfs(root.left,count)
self.dfs(root.right,count)
def sumRootToLeaf(self, root: TreeNode) -> int:
self.total = 0
self.dfs(root,0)
return self.total % (pow(10,9)+7)
2.10、538. 把二叉搜索树转换为累加树
给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater
Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。
例如:
输入: 原始二叉搜索树:
输出: 转换为累加树:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-bst-to-greater-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析:
注意到又是二叉搜索树,是不是可能用到中序遍历?
以前的中序遍历框架:
void traversal(TreeNode* root){
if(root==NULL) return;
traversal(root->left);
//中序遍历访问
traversal(root->right);
}
回忆完毕,现在我们来看上面的遍历框架,如果是中序遍历,就可以输出升序的元素数组,那么现在我想要降序的呢?先输出然后再转置?这是一个方法。
那么如果改变一些框架的代码:
void traversal(TreeNode* root){
if(root==NULL) return;
traversal(root->right);
//中序遍历访问
traversal(root->left);
}
先遍历右子树,然后推导一遍,是不是输出了降序的数组呢?(自行验证)
现在是以降序的方向来遍历树了,降序累加,用数组的思维思考一下,就不难得到结果了。
题解代码(C++):
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* root,int &sum){
if(root==NULL) return;
dfs(root->right,sum);
root->val+=sum;//先改变为新值
sum =root->val;//新值成为累加和
dfs(root->left,sum);
}
TreeNode* convertBST(TreeNode* root) {
int sum = 0;
dfs(root,sum);
return root;
}
};
题解代码(Java):
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int sum = 0;
public void dfs(TreeNode root){
if(root==null) return;
dfs(root.right);
root.val+=this.sum;
this.sum= root.val;
dfs(root.left);
}
public TreeNode convertBST(TreeNode root) {
this.sum=0;
dfs(root);
return root;
}
}
题解代码(Python):
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.temp = 0
def dfs(self,root:TreeNode):
if root is None:
return None
self.dfs(root.right)
root.val+=self.temp
self.temp = root.val
self.dfs(root.left)
def convertBST(self, root: TreeNode) -> TreeNode:
self.temp = 0
self.dfs(root)
return root