1. 剑指 Offer 54. 二叉搜索树的第k大节点
难度 ⭐
🌈 题目描述
给定一棵二叉搜索树,请找出其中第k大的节点。
📢 示例
输入: root = [3,1,4,null,2], k = 1
3
/\
1 4
\
2
输出: 4
分析:
二叉搜索树的一个性质就是,如果按照中序遍历之,一定是从小到大排序的。所以,可以利用这个性质来求第k大。
class Solution {
public:
int kthLargest(TreeNode* root, int k) {
vector<int> arr;
traverse_mid(root,arr);//arr传引用,得到从小到大排序的数组
int len = arr.size();
return arr[len-k];//第k大
}
void traverse_mid(TreeNode* root, vector<int> &arr){//中序遍历
if(root == NULL)
return;
traverse_mid(root->left,arr);//访问左边
arr.push_back(root->val);//访问自己
traverse_mid(root->right,arr);//访问右边
}
};
注:在递归中,如果已经考虑了root == NULL的情况,剩下的情况都是平凡的了,只需考虑任意一种节点,不用区分叶节点/非叶节点。
2. 剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
难度 ⭐
🍵 题目描述
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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。
🎨 思路
虽然这是一道简单题,但是乍一看我还真没有思路…不过知道思路了之后就会发现其实很简单!
首先,从根节点开始,找到节点p和节点q,并把到p和q的路径记录下来,分别记作path_p和path_q.
例如,从6->2的路径为path_p = [6,2]; 从6->4的路径为path_q = [6,2,4]. 取二者第一次不一样的地方,就可以找到最近公共祖先了。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector<TreeNode*> path1 = find(root,p);
vector<TreeNode*> path2 = find(root,q);
int len = min(path1.size(),path2.size());
for(int i = 0;i<len;i++){
if(path1[i]->val!=path2[i]->val)
return path1[i-1]; //find!
}
//all the same
return path1[len-1];
}
vector<TreeNode*> find(TreeNode* root, TreeNode* target){ //record the path from root to target
vector<TreeNode*> ans;
TreeNode* tmp = root;
while(1){
ans.push_back(tmp);
if(tmp->val == target->val)
break;
if(target->val > tmp->val)
tmp = tmp->right;
else
tmp = tmp->left;
}
return ans;
}
};
3. 剑指 Offer 33. 二叉搜索树的后序遍历序列
难度 ⭐⭐
🎀 题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
示例 1:
输入: [1,6,3,2,5] 输出: false
示例 2:
输入: [1,3,2,6,5] 输出: true
🎁 思路
这道题的思路是一个非常典型的树中的递归。由于这是一个后序遍历,每个向量的最后一个值就是二叉树的根节点。如果这的确是一个BST,那么整个向量应该分为[小于根节点的节点,大于根节点的节点]两部分,分别对应左、右孩子。否则,就不是BST。左、右孩子应该都为BST,整个树才为BST。这样,就构造出了递归算法。
class Solution {
public:
bool verifyPostorder(vector<int>& postorder) {
return verify(postorder,0,postorder.size()-1);
}
bool verify(vector<int>& postorder, int begin, int end){
if(end-begin<=0) return true; //单个节点,必然是BST
int root = postorder[end];
int bigger = end; //第一个大于root的节点
for(int i=begin;i<end;i++){
if(postorder[i] > root){
bigger = i;
break;
}
}
for(int i = bigger+1;i<end;i++){
if(postorder[i] < root) //[1,6,3,2,5]
return false;//不是BST
}
int left_begin = begin;
int left_end = bigger-1;
int right_begin = bigger;
int right_end = end-1;
return verify(postorder,left_begin,left_end) && verify(postorder,right_begin,right_end);//左右孩子都得是BST,整个才是BST
}
};
和本题类似的题还有:
- leetcode 98. 验证二叉搜索树