1、学习大纲——二叉树
二叉树( Binary Tree )问题的考点剖析:
1、第一类考察形态:求值,求路径类二叉树问题
2、第二类考察形态:结构变化类二叉树问题
3、第三类考察形态:二叉查找树( Binary Search Tree )类问题:非递归( Non recursion or Iteration )版本的中序遍历 Inorder Traversal
2、典型题
1、求值:一般就是求最大、最小、平均、求和、路径等等。都是在树的路径上操作。
给一棵二叉树,找到有最大平均值的子树。返回子树的根结点。
/**
* 本参考程序来自九章算法,由 @九章算法 提供。版权所有,转发请注明出处。
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right>;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right> = NULL;
* }
* }
*/
//定义一个类 ResultType 作为输出结果
class ResultType {
public:
int sum, size;
ResultType():sum(0), size(0) {}
ResultType(int _sum, int _size): sum(_sum), size(_size) {}
};
class Solution {
public:
/**
* @param root the root of binary tree
* @return the root of the maximum average of subtree
*/
TreeNode* findSubtree2(TreeNode* root) {
// Write your code here
helper(root);
return node;
}
ResultType helper(TreeNode* root) {
if (root == NULL) {
return ResultType();
}
ResultType left = helper(root->left);
ResultType right = helper(root->right);
ResultType result = ResultType(left.sum + right.sum + root->val,
left.size + right.size + 1);
// 这里把除法转为了乘法,我猜是可以避免浮点数的计算
if (node == NULL || result.sum * data.size >= data.sum * result.size) {
data = result;
node = root;
}
return result;
}
private:
TreeNode* node = NULL; //存储当前最优节点
ResultType data; //存储当前最优结果
};
给一棵二叉树, 找到和为最小的子树, 返回其根节点。输入输出数据范围都在int内。
稍作修改即可!
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class ResultType {
public:
int sum;
ResultType():sum(0) {}
ResultType(int _sum): sum(_sum) {}
};
class Solution {
public:
/**
* @param root: the root of binary tree
* @return: the root of the minimum subtree
*/
TreeNode * findSubtree(TreeNode * root) {
helper(root);
return node;
}
ResultType helper(TreeNode* root) {
if (root == NULL) {
return ResultType();
}
ResultType left = helper(root->left);
ResultType right = helper(root->right);
ResultType result = ResultType(left.sum + right.sum + root->val);
if (node == NULL || result.sum < data.sum) {
data = result;
node = root;
}
return result;
}
private:
TreeNode* node = NULL; //存储当前最优节点
ResultType data; //存储当前最优结果
};
给一棵二叉树,找出从根节点到叶子节点的所有路径。
输入:{1,2,3,#,5}
输出:[“1->2->5”,“1->3”]
可以用allpath记录所有路径。排名第一。。。但是再运行一次就倒数,;lintcode奇奇怪怪
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
private:
vector<string> allpath; //用于记录所有路径并输出
string mid; //用于记录根节点
public:
/**
* @param root: the root of the binary tree
* @return: all root-to-leaf paths
*/
string getroot(TreeNode* root){
return to_string(root->val);
}
void dfs(TreeNode* root,vector<string> path){
if(!root->left && !root->right){
allpath.push_back(accumulate(path.begin(), path.end(),mid));
return;
}
if(root->left){
// 输入左子树内容并记录
path.push_back("->");
path.push_back(getroot(root->left));
dfs(root->left,path);
path.pop_back();path.pop_back();
}
if(root->right){
path.push_back("->");
path.push_back(getroot(root->right));
dfs(root->right,path);
path.pop_back();path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> path;
if(root == NULL) return path;
mid = to_string(root->val);
dfs(root,path);
return allpath;
}
};
最近公共祖先
思路:分治的方式,对于中间节点有以下几种情况:
1、左子树或者右子树,其中一个有返回值,则返回有的那个节点值(保证另一个可能是它子节点)
2、都没有,返回NULL
3、都有,返回该节点
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/*
* @param root: The root of the binary search tree.
* @param A: A TreeNode in a Binary.
* @param B: A TreeNode in a Binary.
* @return: Return the least common ancestor(LCA) of the two nodes.
*/
TreeNode * lowestCommonAncestor(TreeNode * root, TreeNode * A, TreeNode * B) {
if (!root || root == A || root == B) {
return root;
}
TreeNode *left = lowestCommonAncestor(root->left, A, B);
TreeNode *right = lowestCommonAncestor(root->right, A, B);
if (left && right) {
return root;
}
return left ? left : right;
}
};
2、结构变化
翻转一棵二叉树。左右子树交换。
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: a TreeNode, the root of the binary tree
* @return: nothing
*/
void invertBinaryTree(TreeNode *root) {
TreeNode *temp = root->left;
root->left = root->right;
root->right = temp;
if (root->left!=NULL) invertBinaryTree(root->left);
if (root->right!=NULL) invertBinaryTree(root->right);
}
};
将一棵二叉树按照前序遍历拆解成为一个 假链表。所谓的假链表是说,用二叉树的 right 指针,来表示链表中的 next 指针。
思路:标准in place 解法
/**
* 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 flatten(TreeNode* root) {
while (root != nullptr) {
if (root->left != nullptr) {
auto most_right = root->left; // 如果左子树不为空, 那么就先找到左子树的最右节点
while (most_right->right != nullptr) most_right = most_right->right; // 找最右节点
most_right->right = root->right; // 然后将跟的右孩子放到最右节点的右子树上
root->right = root->left; // 这时候跟的右孩子可以释放, 因此我令左孩子放到右孩子上
root->left = nullptr; // 将左孩子置为空
}
root = root->right; // 继续下一个节点
}
return;
}
};
作者:hellozhaozheng
链接:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/solution/biao-biao-zhun-zhun-de-hou-xu-bian-li-dai-ma-jian-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3、验证二叉查找树
给定一个二叉树,判断它是否是合法的二叉查找树(BST)
一棵BST定义为:
- 节点的左子树中的值要严格小于该节点的值。
- 节点的右子树中的值要严格大于该节点的值。
- 左右子树也必须是二叉查找树。
- 一个节点的树也是二叉查找树。
Example
样例 1:
输入:{-1}
输出:true
解释:
二叉树如下(仅有一个节点):
-1
这是二叉查找树。
样例 2:
输入:{2,1,4,#,#,3,5}
输出:true
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
bool isValidBST(TreeNode * root) {
return dfs4(root);
}
bool dfs4(TreeNode * root) {
if (root == NULL) {
return true;
}
// Judge the left tree.
if (!dfs4(root->left)) {
return false;
}
// judge the sequence.
// 这里,遍历方法的每一次赋值的root都是从最低到高的,第一次赋值就是最左的子叶,所以每次递归只需要判断一次就可以
if (pre != NULL && root->val <= pre->val) {
return false;
}
pre = root;
// Judge the right tree.
if (!dfs4(root->right)) {
return false;
}
return true;
}
private:
TreeNode* pre = NULL;
};
给一棵二叉搜索树,写一个 KthSmallest 函数来找到其中第 K 小的元素。
思路:如果k为0,返回x即可。如果–k为0,返回当前节点值,否则继续向右子树搜索(右子树的节点值小于当前节点的父亲节点)。
注意这里要用中间变量x,保证k多自减一次!k是这里的局部变量,思路有点绕。
class Solution {
public:
/**
* @param root: the given BST
* @param k: the given k
* @return: the kth smallest element in BST
*/
int kthSmallest(TreeNode * root, int k) {
// write your code here
return find(root, k);
}
int find(TreeNode* root, int& k) {
if (root) {
int x = find(root->left, k);
return !k ? x : !--k ? root->val : find(root->right, k); //如果k为0,返回x即可。如果--k为0,返回当前节点值,否则继续向右子树搜索。
}
}
};
二叉查找树迭代器
经典题背诵!
leetcode上的解答更好一些。
初始化的时候先把root的所有左边的节点入栈
hasNext只要栈不空就是还有下一个元素
next,取出栈顶元素p(当前返回值)。把p的右子树的左节点全部入栈
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class BSTIterator {
private:
stack<TreeNode*> stk;
public:
BSTIterator(TreeNode* root) {
TreeNode *p = root;
while (p) {
stk.push(p);
p = p->left;
}
}
/** @return the next smallest number */
int next() {
TreeNode *p = stk.top(); stk.pop();
int res = p->val;
p = p->right;
while (p) {
stk.push(p);
p = p->left;
}
return res;
}
/** @return whether we have a next smallest number */
bool hasNext() {
return !stk.empty();
}
};
/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator* obj = new BSTIterator(root);
* int param_1 = obj->next();
* bool param_2 = obj->hasNext();
*/
给一棵非空二叉搜索树以及一个target值,找到在BST中最接近给定值的节点值。
中序遍历更新,时间复杂度O(n)。
其实找到相邻的大和小两个数,比一下就好了,时间复杂度O(logn)。
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: the given BST
* @param target: the given target
* @return: the value in the BST that is closest to the target
*/
int closestValue(TreeNode * root, double target) {
// write your code here
int closest = root->val;
while (root) {
if (abs(closest - target) >= abs(root->val - target)) {
closest = root->val;
}
root = target < root->val ? root->left : root->right;
}
return closest;
}
};
closest binary search tree value
给定一棵非空二叉搜索树以及一个target值,找到 BST 中最接近给定值的 k 个数。
报错!需要再修改!
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: the given BST
* @param target: the given target
* @param k: the given k
* @return: k values in the BST that are closest to the target
*/
stack<TreeNode* > findtarget(TreeNode * root,double target){
stack<TreeNode* > bfvector;
while(root){
bfvector.push(root);
if (root->val > target){
root = root->left;
}
else{
root = root ->right;
}
}
return bfvector;
}
void bef(stack<TreeNode*> stack){
TreeNode* node=stack.top();
//右子树最左子叶
if(node->left == NULL){
node = stack.top(); stack.pop();
while(stack.size()&&stack.top()->left==node){
node = stack.top(); stack.pop();
}
return;
}
//左子树最右子叶
else{
node = node->left;
while(node){
stack.push(node);
node = node->right;
}
}
return;
}
void aft(stack<TreeNode*> stack){
TreeNode* node = stack.top();
if(node->right == NULL){
node = stack.top(); stack.pop();
while(stack.size()&&stack.top()->right==node){
node = stack.top(); stack.pop();
}
return;
}
else{
node = node->right;
while(node){
stack.push(node);
node = node->left;
}
}
return;
}
vector<int> closestKValues(TreeNode * root, double target, int k) {
vector<int> output;
if(!root||k==0) return output;
stack<TreeNode*> bfvector = findtarget(root,target);
stack<TreeNode*> afvector = findtarget(root,target);
if(target < bfvector.top()->val){
bef(bfvector);
}else{
aft(afvector);
}
//找到最接近的root
for(int i = 0;i<k;i++){
if(bfvector.size()==0||afvector.size()!=0 && (target - bfvector.top()->val) > (afvector.top()->val-target)){
output.push_back(afvector.top()->val);
aft(afvector);
}else{
output.push_back(bfvector.top()->val);
bef(bfvector);
}
}
return output;
}
};
补充学习二叉查找树的增删查改!