LeetCode 530. 二叉搜索树的最小绝对差
题目链接:LeetCode 530. 二叉搜索树的最小绝对差
思想:本题可以根据昨天的验证二叉搜索树的思路来,通过中序遍历得到一个升序的数组,然后笔案例这个升序数组,如果两个数之差小于目前记录的值的话,就更换一次。
代码如下:
void bianli(TreeNode* cur, vector<int>& vec){
if (!cur) return;
bianli(cur->left, vec);
vec.push_back(cur->val);
bianli(cur->right, vec);
}
int getMinimumDifference(TreeNode* root) {
vector<int> xulie;
if (!root) return 0;
bianli(root, xulie);
int min = INT_MAX;
for (int i = 1; i < xulie.size(); i++){
if (abs(xulie[i] - xulie[i - 1]) <= min){
min = abs(xulie[i] - xulie[i - 1]);
}
}
return min;
}
LeetCode 501. 二叉搜索树中的众数
思想:本题首先需要一个数组来接收众数,其次就是根据二叉搜索树的性质,采用中序遍历。其次就需要两个节点指针,一个是父亲节点,一个是当前节点,用于判断前后值是否一样。如果一样的话,就让记录众数频次的值+1;如果不一样,就让记录众数频次的值等于1;如果前一个节点是NULL的话,证明是树的根节点,记录众数频次值等于1。同时,记录一个最大众数频次,如果当前众数频次等于最大众数频次的话,将当前节点的值压入众数数组;如果当前众数频次大于最大众数频次的话,更新最大众数频次,并将众数数组元素清空,把当前节点数值压入众数数组。
代码如下:
int count = 0;
int maxCount = 0;
TreeNode* pre = NULL;
vector<int> mode;
void bianli(TreeNode* cur){
if (!cur) return;
bianli(cur->left);
if (pre == NULL) count = 1;
else if (pre->val == cur->val) count++;
else count = 1;
pre = cur;
if (count == maxCount){
mode.push_back(cur->val);
} else if (count > maxCount){
maxCount = count;
mode.clear();
mode.push_back(cur->val);
}
bianli(cur->right);
}
vector<int> findMode(TreeNode* root) {
count = 0;
maxCount = 0;
mode.clear();
bianli(root);
return mode;
}
LeetCode 236. 二叉树的最近公共祖先
思想:本题需要先去确定终止条件,即如果当前节点是要找的p或者q节点或当前节点为空,就返回当前节点。然后去遍历整个数的节点,如果左右子树的返回结果都存在,就返回当前节点;如果子树返回节点为空,右子树不为空,就返回右子树;反之返回左子树。
代码如下:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == p || root == q || !root) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left && right) return root;
if (!left && right) return right;
else if (left && !right) return left;
else return NULL;
}
LeetCode 235. 二叉搜索树的最近公共祖先
题目链接:LeetCode 235. 二叉搜索树的最近公共祖先
思想:本题就可以基于上题来优化,如果当前节点的值小于p 大于q 或者 小于q 大于p,就继续遍历左右子树;如果当前节点的值大于节点p q,就遍历左子树;如果当前节点的值小于节点p q,就遍历右子树。
代码如下:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == p || root == q || root == NULL) return root;
TreeNode* left = NULL;
TreeNode* right = NULL;
if (p->val < root->val < q->val || q->val < root->val < p->val) {
left = lowestCommonAncestor(root->left, p, q);
right = lowestCommonAncestor(root->right, p, q);
} else if (root->val > p->val && root->val > q->val) {
left = lowestCommonAncestor(root->left, p, q);
} else {
right = lowestCommonAncestor(root->right, p, q);
}
if (left && right) return root;
else if (!left && right) return right;
else if (left && !right) return left;
else return NULL;
}
LeetCode 701. 二叉搜索树中的插入操作
题目链接:LeetCode 701. 二叉搜索树中的插入操作
思想:本题其实很简单,就遍历二叉搜索树,遇到空节点就插入。怎么保证就是正确插入呢,即插入之后还是二叉搜索树。即遇到当前节点值大于val 时候就遍历左节点;反之遍历右节点即可。
代码如下:
TreeNode* pre;
void bianli(TreeNode* cur, int val){
if (!cur) {
TreeNode* node = new TreeNode(val);
if (val < pre->val) pre->left = node;
else if (val > pre->val) pre->right = node;
return;
}
pre = cur;
if (cur->val < val) bianli(cur->right, val);
if (cur->val > val) bianli(cur->left, val);
}
TreeNode* insertIntoBST(TreeNode* root, int val) {
pre = new TreeNode(0);
if (!root) {
pre->val = val;
return pre;
}
bianli(root, val);
return root;
}
LeetCode 450. 删除二叉搜索树中的节点
题目链接:LeetCode 450. 删除二叉搜索树中的节点
思想:本题比插入复杂,因为删除涉及到一个问题,即二叉搜索树的结构改变。所以遇到删除的节点有以下几种情况:
- 当前节点没有左右孩子,直接删去即可
- 当前节点有左孩子,没有右孩子,将当前节点用节点的左孩子代替
- 当前节点没有左孩子,有右孩子,将当前节点用节点的右孩子代替
- 当前节点既有左孩子又有右孩子,将左孩子放进右子树的最左面的节点下面,删除当前节点即可
代码如下:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return NULL;
if (root->val == key && !root->left && !root->right){
delete root;
return NULL;
} else if (root->val == key && !root->left && root->right){
auto retNode = root->right;
delete root;
return retNode;
} else if (root->val == key && root->left && !root->right){
auto retNode = root->left;
delete root;
return retNode;
} else if (root->val == key && root->left && root->right){
TreeNode* cur = root->right;
while (cur->left != nullptr){
cur = cur->left;
}
cur->left = root->left;
TreeNode* temp = root;
root = root->right;
delete temp;
return root;
}
if (root->val > key) root->left = deleteNode(root->left, key);
if (root->val < key) root->right = deleteNode(root->right, key);
return root;
}
总结
这几天学习到了一个新的知识点,就是遍历二叉树的方式。
bianli(cur->left);
bianli(cur->right);
这种遍历方式一般用于遍历二叉树的边。
cur->left = bianli(cur->left);
cur->right = bianli(cur->right);
这种遍历方式一般用于遍历整个二叉树。
主要情况分为以下几种:
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。