二叉树Part06

530.二叉搜索树的最小绝对差

思路

把遍历到的节点都加入vec中,在互减得出答案。

题解

递归法

好久没写,手生了,第一次写成前序遍历了,没有利用到二叉搜索树的特性(中序遍历时是从小到大的)

class Solution {
private:
  std::vector<int> vec;
  void traversal(TreeNode *node) {
    vec.push_back(node->val);
    if (node->left)
      traversal(node->left);
    else
      return;
    if (node->right)
      traversal(node->right);
    else
      return;
  }

public:
  int getMinimumDifference(TreeNode *root) {
    vec.clear();
    traversal(root);
    if (vec.size() < 2)
      return 0;
    int result = INT_MAX;
    for (int i = 1; i < vec.size(); i++) { // 统计有序数组的最小差值
      result = min(result, vec[i] - vec[i - 1]);
    }
    return result;
  }
};

修改遍历逻辑即可

 void traversal(TreeNode *root) {
    if (root == NULL) return;
    traversal(root->left);
    vec.push_back(root->val); // 将二叉搜索树转换为有序数组
    traversal(root->right);
  }

此外,我们还可以在遍历中进行计算,使用pre指针和cur指针

class Solution {
private:
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);  // 右
}
public:
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return result;
    }
};

迭代法

利用栈模拟递归

501.二叉搜索树中的众数

思路

题解

初见写出来的狗屎代码。这下知道用中序遍历了,但是关于最大频率的处理不对。

class Solution {

private:
    std::vector<int> vec;
    void traversal(TreeNode* root) {
        if (root == nullptr) return;
        traversal(root->left);
        vec[root->val]++;
        traversal(root->right);
    }
public:
    vector<int> findMode(TreeNode* root) {
        traversal(root);
        int idx = 0;
        int cur = 0;
        int value = 0;
        std::vector<int> res;
        for(auto it : vec) {
            if (it > cur) {
                cur = it;
                value = idx;
            }
            idx++;
        }
        res.push_back(value);
        return res;
    }
};

用map遍历两次,应该算暴力解法

class Solution {
private:
    unordered_map<int, int> map; // 统计频率
    void traversal(TreeNode* root) {
        if (root == nullptr) return;
        traversal(root->left);
        map[root->val]++; // 统计频率
        traversal(root->right);
    }
public:
    vector<int> findMode(TreeNode* root) {
        map.clear();
        traversal(root);
        vector<int> result;
        int maxCount = 0;
        
        // 第一次遍历找到最大频率
        for (const auto& pair : map) {
            maxCount = max(maxCount, pair.second);
        }
        
        // 第二次遍历找出所有出现次数等于maxCount的元素
        for (const auto& pair : map) {
            if (pair.second == maxCount) {
                result.push_back(pair.first);
            }
        }
        return result;
    }
};

将map转换成vec进行排序

class Solution {
private:

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 (const pair<int, int>& a, const pair<int, int>& b) {
    return a.second > b.second;
}
public:
    vector<int> findMode(TreeNode* root) {
        unordered_map<int, int> map; // key:元素,value:出现频率
        vector<int> result;
        if (root == NULL) return result;
        searchBST(root, map);
        vector<pair<int, int>> vec(map.begin(), map.end());
        sort(vec.begin(), vec.end(), cmp); // 给频率排个序
        result.push_back(vec[0].first);
        for (int i = 1; i < vec.size(); i++) {
            // 取最高的放到result数组中
            if (vec[i].second == vec[0].second) result.push_back(vec[i].first);
            else break;
        }
        return result;
    }
};

利用二叉搜索树的特性进行求解。因为中序遍历出来的元素是个有序数组,所以我们只需要比较相邻两个元素就可以得出出现频率了。

我们仍然需要使用pre指针和cur指针的技巧。

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;
    }
};

增强for循环中使用 const auto& 的原因:

  1. 性能考虑

    • & (引用)避免了对 map 中元素的拷贝
    • 直接引用原始数据,减少内存使用和复制开销
  2. const 的作用

    • 保证在遍历过程中不会修改 map 中的数据
    • 增加代码安全性
    • 明确表达"只读"意图
  3. auto 的作用

对比不同写法:

// 1. 不推荐: 会产生拷贝

for (auto pair : map) { ... }

// 2. 不推荐: 可能修改数据

for (auto& pair : map) { ... }

// 3. 推荐: 既高效又安全

for (const auto& pair : map) { ... }

这样写既保证了性能,又保证了数据安全性。

236.二叉树的最近公共祖先

思路

利用了前序遍历的回溯思想。

自底向上的寻找公共祖先。首先从遍历左子树开始,如果在左子树中的某一个节点中发现了指定节点p,就立马return此节点给其父节点,这样left就有了一个值,这时候我们就在刚刚找到的p节点的父节点处,此时我们寻找这个节点的右子树,看看是否能寻找到右节点,如果能找到的话,那这个节点就是我们要找的公关祖先,所以我们直接return这个节点到其父节点,在这个公共祖先的父节点中,我们找到的节点可能是左子树也可能是右子树,所以只需要左右子树一个有值,我们就返回那个不为null的值,这样就实现了传递的过程。

表述不太好,可以结合着代码和一下图片理解。

202102041512582.png

题解

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == q || root == p || root == NULL) 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 right;
        else if (left != NULL && right == NULL) return left;
        else  { //  (left == NULL && right == NULL)
            return NULL;
        }

    }
};
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇