二叉搜索树
二叉搜索树的最小绝对差
题意:求树中任意两不同节点值之间的最小差值 。
思路:这回要使用前后指针了。
使用两个指针(前指针和后指针),对指向的结点的值进行相减,如果值大于maxlen就更新这个值。
核心代码
void trival(TreeNode* root){if(root == nullptr){return ; }trival(root->left) ; cur = root ; if(prev){int dif = abs(cur->val - prev->val );if(dif < mindif ){mindif = dif ; }}prev = cur ; trival(root->right) ; }
二叉搜索树中的众数
题意:是找到频率最高的元素 。
思路:我没有做到不用额外的空间的最优算法 。 由于我想一步做多步。
只是使用map<int ,int> 键作为每个节点的值,值为每个节点的值出现的次数 。
使用前序遍历将整个树遍历。之后把map的元素放入到vector<pair<int,int >> 对其进行排序,最后输出频率最高的数。
核心代码
class Solution {
public:vector<pair<int , int>> res ; // 存储当前TreeNode * pre = nullptr ; int l = 0 , r =0 ;int maxlen = 0 ; map<int ,int > m ; void trival(TreeNode * cur){if(cur == nullptr) {return ; } trival(cur->left) ;m[cur->val] ++ ; trival(cur->right) ; }struct comp{bool operator()(const pair<int,int> & lhs ,const pair<int ,int > & rhs){return lhs.second > rhs.second ; }} ; vector<int> findMode(TreeNode* root) {vector<int> tres ;if(root && root->val == 0&& root->left == nullptr && root->right == nullptr){tres.push_back(0) ; return tres ; } trival(root);for(auto it : m){res.push_back(it) ; }sort(res.begin() ,res.end(), comp() ) ; tres.push_back(res[0].first) ; cout<<res.size()<<endl ; for(int i = 0 ; i< res.size() ; ++ i){if(i>0){if(res[i].second == res[i-1].second){tres.push_back(res[i].first) ; }else{break ; }}}return tres ; }
};
不用额外空间的的思路: 由于搜素二叉树的性质,我们使用中序遍历可以做到,使用一个cnt来计数相同的元素。在中序遍历的过程中递归体每前一个元素和现在的元素不一样了,那么这个cnt重新等于1。并且看是否更新值。同时需要清空vector< int > res 因为 这个只存最大的元素。 我们也是贪婪地寻找。最后一定会找到频率最高的元素。 如果当前得到的cnt == maxlen 就将这个元素加入res.
总结:解题的步骤,一个阶段只做一件事。 就比如这道题,我已经想到用搜索二叉树的性质,但是在计数的时候我想的是双指针法,这就比直接计数复杂了, 并且难以操作,就放弃了。 因此要不拘于一种方法。简单的计数也是可以使用的。
核心代码
void trival(TreeNode* root){if(root== nullptr){return ; }trival(root->left) ;if(pre == nullptr) // 当pre等于null {cnt = 1 ; }else if(pre->val == root->val){cnt++ ; }else if(pre->val != root->val){cnt = 1 ; // 重新计算相同的数}if(cnt> maxlen) // 当这个值的数量大于原先的值的个数时,那么{maxlen = cnt ; res.clear() ;res.push_back(root->val) ; }else if(cnt == maxlen) // 当cnt等于maxlen时。就{res.push_back(root->val) ; }pre = root ; trival(root->right) ; }
二叉树的最近公共祖先
是一个难题:
1被卡哥说的,我直接看视频 。
但是其实没有那么难;
注意:1.以前也做过从下往上遍历的题; 就是使用后序遍历, 先到叶子结点后,再返回上一层递归。当然返回类型是TreeNode * ; 以便于判断;
2.本层递归要做什么其实就是我这个递归要做什么:要判断左右子树是否包含p或q节点。 如果包含那么就返回本节点到上层递归。
3.递归边界:当节点是null时,就返回,当节点找到了p或者q就返回。
核心代码
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){if(root == NULL){return NULL ; } if(root == p || root == q) // 边界条件 , 遇到p 或 q 就返回本节点 。 {return root ; } TreeNode * left = lowestCommonAncestor(root->left , p , q) ; TreeNode * right = lowestCommonAncestor(root->right , p ,q) ;if(left && right ) return root ; // 如果从左子树有值 。 并且右子树有值 ; 如果左子树和右子树都找到了值那么本节点就是最近公共祖先节点。 if(left && right == NULL) return left ; // 如果左子树有值,就返回左子树的值 。 因为在左子树找到了值 。 if(left == NULL && right ) return right ; // return NULL ; }
另外总结:
1.求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。
2.在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
3.要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。 因为是层层往上递归返回