目录
- 530.二叉搜索树的最小绝对差
- 501.二叉搜索树中的众数
- 105.从中序与前序遍历序列构造二叉树
- 总结
- 收获
530.二叉搜索树的最小绝对差
文章链接:代码随想录
题目链接:题目
思路:用中序遍历遍历一遍 BST 的所有节点得到有序结果,然后在遍历过程中计算最小差值即可
需要用一个pre节点记录一下cur节点的前一个节点:在递归中记录前一个节点的指针
/*** 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 res = INT_MAX;TreeNode * prev = nullptr;int getMinimumDifference(TreeNode* root) {traverse(root);return res;}void traverse(TreeNode* root){if(!root) return;traverse(root->left);if(prev){res = min(res, abs(root->val - prev->val));}prev = root;traverse(root->right);}
};
501.二叉搜索树中的众数
文章链接:代码随想录
题目链接:题目
思路:
这道题需要用到「遍历」的思维。
BST 的中序遍历有序,在中序遍历的位置做一些判断逻辑和操作有序数组差不多,很容易找出众数。
注意:
频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集(以下代码为result数组),因为结果集之前的元素都失效了
class Solution {
private: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 (pre->val == cur->val) { // 与前一个节点数值相同count++;} else { // 与前一个节点数值不同count = 1;}pre = cur; // 更新上一个节点if (count == maxCount) { // 如果和最大值相同,放进result中result.push_back(cur->val);}if (count > maxCount) { // 如果计数大于最大值频率maxCount = count; // 更新最大频率result.clear(); // 很关键的一步,不要忘记清空result,之前result里的元素都失效了result.push_back(cur->val);}searchBST(cur->right); // 右return ;}public:vector<int> findMode(TreeNode* root) {count = 0;maxCount = 0;pre = NULL; // 记录前一个节点result.clear();searchBST(root);return result;}
};
105.从中序与前序遍历序列构造二叉树
文章链接:代码随想录
题目链接:题目
思路:
构造二叉树,第一件事一定是找根节点,然后想办法构造左右子树。
二叉树的前序和中序遍历结果的特点如下:
前序遍历结果第一个就是根节点的值,然后再根据中序遍历结果确定左右子树的节点。
/*** 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:unordered_map<int, int> hash;TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {for (int i = 0; i < inorder.size(); i++){hash[inorder[i]] = i;}return buildTree(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);}TreeNode* buildTree(vector<int>&preorder,int pl, int pr, vector<int>& inorder, int il, int ir){if(pl > pr) return nullptr;auto val = preorder[pl];//根据前序遍历的值 从哈希表中找到对应中序遍历的下标int k = hash[val];int lLength = k - il;TreeNode* root = new TreeNode(val);//pl + lLength有点没懂 //k - 1 - il// pl + 1 + k - 1 - il =>pl + k - il => pl + kroot->left = buildTree(preorder, pl + 1, pl + lLength, inorder, il, k - 1);root->right = buildTree(preorder, pl + lLength + 1, pr, inorder, k + 1, ir);return root;}
};
总结
二叉树解题的思维模式分两类:
1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。
2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。
无论使用哪种思维模式,你都需要思考:
如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。
收获
补之前的卡