530. 二叉搜索树的最小绝对差
本题看起来不好做,其实利用BST的性质思路就很简单了。利用BST中序遍历递增的性质,只要将当前遍历的结点与前一个结点比较即可。这里使用递归法来写。
(当不清楚递归中是否需要返回值或单纯的需要遍历二叉树的情况,可以尝试使用额外的递归函数)
递归三部曲:
- 输入输出:这里输入自然是结点;输出其实我一开始的思路是返回值为
int
,然后利用返回值进行对比,后来发现行不通,就直接利用全局变量来作为答案,这样不需要处理返回值那么递归函数的返回类型为void
; - 终止条件:遍历二叉树,终止条件自然为
if(cur == NULL)
; - 单层递归逻辑:BST是中序遍历,所以结点的处理顺序是左中右
下面是具体的代码:
int result = INT_MAX;
TreeNode* pre = NULL;
void travesal(TreeNode* cur){
if(cur == NULL) return;
travesal(cur->left);
if(pre && cur->val - pre->val < result){
result = cur->val - pre->val;
}
pre = cur;
travesal(cur->right);
}
定义两个全局变量,一个用来存放答案,一个用来存放pre结点,这种手法在前一天的题目也见到了。最后在主函数调用即可。
501.二叉搜索树中的众数
本题有两个地方需要注意的:
- 二叉树的结点值是可以重复的
- 众数可以是多个,只要是出现频次相同就作为答案输出
考虑使用递归法来写,下面是递归三部曲:
- 输入输出:本题和上一题差不多,额外写一个递归函数,返回值为
void
; - 终止条件:
if(cur == NULL)
; - 单层递归逻辑:还是使用pre指针,令其与当前结点对比,遍历顺序还是中序
首先需要定义几个全局变量:
TreeNode* pre = NULL;
int count = 0; //统计当前的频次
int max_count = 0; //记录最大频次
vector<int> ans; //输出答案
下面是递归函数:
void travesal(TreeNode* cur){
if(cur == NULL) return;
travesal(cur->left);
if(pre == NULL) count = 1; //空节点count为1
else if(pre->val == cur->val) count++;
else count = 1; //不等的情况
pre = cur;
//特殊的处理
if(count == max_count) ans.push_back(cur->val); //满足条件输入
if(count > max_count){ //当出现频次更高的情况,将之前的答案全部清除
max_count = count; //更新最大频次
ans.clear();
ans.push_back(cur->val); //输入当前答案
}
travesal(cur->right);
}
这里需要注意对pre == NULL
时,count置为1;在答案输出处理逻辑上,使用先输入再判断的方式,可以在一次遍历中就输出答案。
236. 二叉树的最近公共祖先
本题还是很有难度的,乍一看就没什么思路,然后再想了一些没用的判断条件,其实不用想那么复杂,看完卡哥的视频后豁然开朗。首先需要想清楚本题使用自下而上的遍历方式,也就是使用后序遍历最后处理中结点。当遇到符合条件的结点时直接向上一层返回,除非p和q都不包含返回NULL,其余的情况都往上返回存在p或q的结点,这样想明白递归的过程就会发现这样会自然而然的返回最近的公共祖先。
递归三部曲:
- 输入输出:这里直接使用给出的主函数递归,返回值类型为
TreeNode*
; - 终止条件:
if(root == NULL) return NULL
;重点需要注意的是本题结点本身也算是自己的祖先,所以要加上if(root == q || root == p) return root;
; - 单层递归逻辑:只要注意使用后序遍历就行
如果函数返回值为NULL,就说明当前结点没有题目要求的子树,代码如下:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL) return NULL;
if(root == q || root == p) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
//只要遇到符合条件的就返回结点
if(left != NULL && right != NULL) return root;
if(left != NULL && right == NULL) return left;
if(left == NULL && right != NULL) return right;
return NULL;
}
代码很简洁,主要是得想明白,另外:结点本身也算是自己的祖先需要注意。