530.二叉搜索树的最小绝对差
1.因为二叉搜索树中序遍历是个非递减序列,所以最小绝对值差一定在中序遍历的相邻结点取到。朴素思想是把二叉树的中序遍历用数组输出,然后处理这个数组找到最小绝对值差。(以迭代法求取数组为例)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public://迭代法,按中序遍历转换为数组比较
int min=INT_MAX;
vector<int> inorderTraversal(TreeNode* root){
vector<int> result;
stack<TreeNode*> st;
TreeNode* cur=root;
while(cur||!st.empty()){
if(cur){
st.push(cur);
cur=cur->left;
}
else{
cur=st.top();
st.pop();
result.push_back(cur->val);
cur=cur->right;
}
}
return result;
}
int getMinimumDifference(TreeNode* root) {
vector<int> result=inorderTraversal(root);
for(int i=0;i<result.size()-1;i++){
if(result[i+1]-result[i]<min)
min=result[i+1]-result[i];
}
return min;
}
};
2.其实在中序遍历二叉搜索树的过程中就可以顺带求出最小值,以递归法为例
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public://递归中计算
int result = INT_MAX;
TreeNode* pre = NULL;
void traversal(TreeNode* cur) {
if (cur == NULL) return;
traversal(cur->left); // 左
if (pre != NULL){ // 中
result = min(result, cur->val - pre->val);
}
pre = cur; // 记录前一个
traversal(cur->right); // 右
}
int getMinimumDifference(TreeNode* root) {
traversal(root);
return result;
}
};
501.二叉搜索树中的众数
1.一个朴素思想就是遍历这个二叉树并记录每个元素出现的频率,再按照频率从大到小排序,输出频率最大的一个或多个元素值。(普适方法,所有的二叉树都能处理)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public://普通法(一般二叉树也能处理)
void searchBST(TreeNode* cur,unordered_map<int,int>& map){//遍历函数
if(cur==NULL) return;
map[cur->val]++;
searchBST(cur->left,map);
searchBST(cur->right,map);
return;
}
bool static cmp(pair<int,int> a,pair<int,int> b){//比较函数
return a.second>b.second;
}
vector<int> findMode(TreeNode* root) {
unordered_map<int,int> umap;
searchBST(root,umap);
vector<pair<int,int>> copy;
for(auto x:umap)//map不能直接排序,需要先复制到一个同类型数组中
copy.push_back({x.first,x.second});
sort(copy.begin(),copy.end(),cmp);
vector<int> result;
for(auto y:copy){//将频率最高的所有元素加入到返回数组中
if(y.second==copy[0].second)
result.push_back(y.first);
}
return result;
}
};
2.在朴素思想中,我们没有用到二叉搜索树的特性,即它的中序遍历是一个单调的序列。有着相同元素值的结点一定是相邻的,那我们就可以在中序遍历的过程中记录最大频率对应的元素值。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public://特殊递归法
int maxcount=0;//初始化一个最大值
int count=0;
TreeNode* pre=NULL;//初始化一个前置指针,方便记录相邻元素之差
vector<int> result;
void searchBST(TreeNode* cur){
if(cur==NULL) return;
searchBST(cur->left);//左
if(pre==NULL) count=1;//中
else if(cur->val==pre->val) count++;//相邻元素值相等,频率++
else count=1;//不相等则重新从1开始计算频率
pre=cur;
if(count==maxcount) result.push_back(cur->val);//出现次数最多的元素有多个则一起加进去
if(count>maxcount){//出现了频率更高的元素,则更新最大值,清除数组,加入新元素
maxcount=count;
result.clear();
result.push_back(cur->val);
}
searchBST(cur->right);//右
return;
}
vector<int> findMode(TreeNode* root) {
searchBST(root);
return result;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public://迭代法
vector<int> findMode(TreeNode* root) {
stack<TreeNode*> st;
TreeNode* cur=root;
int maxcount=0;
int count=0;
TreeNode* pre=NULL;
vector<int> result;
while(cur||!st.empty()){
if(cur){
st.push(cur);
cur=cur->left;
}
else{
cur=st.top();
st.pop();
if(pre==NULL) count=1;
else if(cur->val==pre->val) count++;
else count=1;
pre=cur;
if(count==maxcount) result.push_back(cur->val);
if(count>maxcount){
maxcount=count;
result.clear();
result.push_back(cur->val);
}
cur=cur->right;
}
}
return result;
}
};
236. 二叉树的最近公共祖先
1.朴素思想:先构造一个函数判断一个结点是不是另一个结点的祖先,我采用的是先序遍历递归。
之后层序遍历这个二叉树,是两个结点的公共祖先就另返回结点接收。逐层遍历二叉树,出现新的公共祖先结点就更新返回结点,最后更新的祖先节点一定是最近的公共祖先结点。(理论存在,实践过是过了,执行时间1300多ms,把我自己都看笑了)
/**
* 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 isAncestor(TreeNode* cur,TreeNode* node){//判断公共祖先函数
if(cur==NULL) return false;
if(cur==node) return true;
if(isAncestor(cur->left,node)) return true;
if(isAncestor(cur->right,node)) return true;
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
TreeNode* result=NULL;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size=que.size();
for(int i=0;i<size;i++){
TreeNode* cur=que.front();
que.pop();
if(isAncestor(cur,p)&&isAncestor(cur,q))
result=cur;//有新的祖先结点就更新
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
return result;
}
};
2.1300多ms实在是有些丢人,有什么办法能减少运行时间呢?有的,那就是剪枝。因为公共结点可能是一个结点本身,所以我优先处理了p是q的祖先和q是篇的祖先,进行了剪枝。结果奇迹出现了,提交结果出现了一个双超过99%的评价!剪枝大法好啊!
/**
* 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 isAncestor(TreeNode* cur,TreeNode* node){
if(cur==NULL) return false;
if(cur==node) return true;
if(isAncestor(cur->left,node)) return true;
if(isAncestor(cur->right,node)) return true;
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(p->left==q||p->right==q) return p;//剪枝
if(q->left==p||q->right==p) return q;
if(isAncestor(p,q)) return p;
if(isAncestor(q,p)) return q;
TreeNode* result=NULL;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size=que.size();
for(int i=0;i<size;i++){
TreeNode* cur=que.front();
que.pop();
if(isAncestor(cur,p)&&isAncestor(cur,q))
result=cur;
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
return result;
}
};
3.递归法,为什么采用后序遍历?因为递归逻辑要求我们这样做,先处理左右子树,根据左右子树的结果进行返回。
/**
* 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==p||root==q||root==NULL) return root;
TreeNode* left=lowestCommonAncestor(root->left,p,q);
TreeNode* right=lowestCommonAncestor(root->right,p,q);
if(left&&right) return root;//返回逻辑
if(left==NULL) return right;
else return left;
}
};
今日总结:剪枝大法好啊!