Leedcode刷题 | Day18_二叉树06

 一、学习任务

  • 530.二叉搜索树的最小绝对差代码随想录
  • 501.二叉搜索树中的众数
  • 236. 二叉树的最近公共祖先

二、具体题目

1.530二叉搜索树的最小绝对差

        给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。

重点:差的最小绝对值之所以可以只比较相邻的值,是因为该树是二叉搜索树,按照中序遍历是一个递增的数组,差的最小绝对值只会可能发生在相邻的数字之间。

经验:

  1. 遇到在二叉搜索树上求什么最值,求差值之类的,都要思考一下二叉搜索树可是有序的,要利用好这一特点。
  2. 双指针大法好:在递归遍历的过程中记录前后两个指针,是一个非常有用的小trick。

        和前一个题,验证二叉搜索树,是一样的思路,一个指针指向中序遍历的前一个结点,一个指针指向后一个,从而达到比较大小(验证二叉搜索树),或者比较差值(二叉搜索树的最小绝对差)的效果。

递归法(中序-双指针):

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

2.501二叉搜索树中的众数

给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。

假定 BST 有如下定义:

  • 结点左子树中所含结点的值小于等于当前结点的值
  • 结点右子树中所含结点的值大于等于当前结点的值
  • 左子树和右子树都是二叉搜索树

代码如下:

也使用双指针

class Solution {
private:
    int maxCount = 0; // 最大频率
    int count = 0; // 统计频率
    TreeNode* pre = NULL;
    vector 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 findMode(TreeNode* root) {
        count = 0;
        maxCount = 0;
        pre = NULL; // 记录前一个节点
        result.clear();

        searchBST(root);
        return result;
    }
};

如果只是普通二叉树(无序),不是二叉搜索树,则使用哈希表-map(不连续)
 

class Solution {
private:

void searchBST(TreeNode* cur, unordered_map& map) { // 前序遍历
    if (cur == NULL) return ;
    map[cur->val]++; // 统计元素频率
    searchBST(cur->left, map);
    searchBST(cur->right, map);
    return ;
}
bool static cmp (const pair& a, const pair& b) {
    return a.second > b.second;
}
public:
    vector findMode(TreeNode* root) {
        unordered_map map; // key:元素,value:出现频率
        vector result;
        if (root == NULL) return result;
        searchBST(root, map);
        vector> 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;
    }
};

3.236二叉树的最近公共祖先

        给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

        百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

        遇到这个题目首先想的是要是:自底向上查找,这样就可以找到公共祖先。

        那么二叉树如何可以自底向上查找呢?回溯过程就是自底向上查找的过程。

        后序遍历(左右中)就是天然的回溯过程,可以根据左右子树的返回值,来处理中节点的逻辑。

        接下来就看如何判断一个节点是节点q和节点p的公共祖先呢。

  • 情况一:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。 
  • 情况二:就是节点本身p(q),它拥有一个子孙节点q(p)。 
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *curA = headA;
        ListNode *curB = headB;
        int lenA = 0;
        int lenB = 0;

        while (curA != nullptr) { // 求链表A长度
            lenA++;
            curA = curA->next;
        }
        while (curB != nullptr) { // 求链表B长度
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        // 默认A链表更长
        if (lenB > lenA) {
            swap (lenA, lenB);
            swap (curA, curB);
        }
        int gap = lenA - lenB; // 求长度差值
        // 让A B尾部对齐
        while (gap) {
            curA = curA->next;
            gap--;
        }
        // 遍历两个链表,看哪个指针相同
        while (curA != nullptr) {
            if (curA == curB) {
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return nullptr;
    }
};

你可能感兴趣的:(算法,c++,数据结构,leetcode)