算法训练1-day16-二叉树

31 阅读3分钟

今天是二叉树

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

中序遍历,用一个指针记录前一个节点,计算当前节点与前一节点差值,与记录的最小值比较即可;因为二叉搜索树的中序遍历结果是一个有序的序列,我们只需要两两比较相邻的数,找出它们的最小差值即可

AC代码:

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return _constructMaximumBinaryTree(nums, 0, nums.size() - 1);
    }

    TreeNode* _constructMaximumBinaryTree(vector<int>& nums, int left, int right) {
        if (left > right) return nullptr;

        int maxPos = left;
        int maxVal = nums[left];
        for (int i = left + 1; i <= right; ++i) {
            if (nums[i] > nums[maxPos]) {
                maxVal = nums[i];
                maxPos = i;
            }
        }
        TreeNode* root = new TreeNode(maxVal);

        root->left = _constructMaximumBinaryTree(nums, left, maxPos - 1);
        root->right = _constructMaximumBinaryTree(nums, maxPos + 1, right);

        return root;
    }
};
  1. 501. 二叉搜索树中的众数

二叉搜索树的问题一般可以从中序遍历入手。

对于这道题,要求二叉搜索树的众数,因为二叉搜索树的中序遍历是有序的,因此我们可以先从有序数组如何求众数入手,即遍历一遍,在过程中记录每个数出现的次数,看是不是比之前记录的最大出现次数大,如果更大,那就代表出现了新的候选项,记录它,并抛弃之前记录的无效结果;如果相等,那就代表是复数的答案,记录它就行。

对于二叉树的遍历,要比较中序遍历相邻两节点的值,可以用一个指针记录前一个节点的值。

AC代码:

class Solution {
public:
TreeNode* prev;
    vector<int> findMode(TreeNode* root) {
        prev = nullptr;
        vector<int> ans;
        int count = 1;
        int maxCount = 0;
        inorder(root, ans, count, maxCount);
        return ans;
    }
	
	// count和maxCount都要传递引用,因为遍历左子树时这两者可能会发生改变
    void inorder(TreeNode* root, vector<int>& ans, int& count, int& maxCount)
    {
        if(root == nullptr) return;

        inorder(root->left, ans, count, maxCount);

        if(prev != nullptr){
            if(prev->val == root->val){
                count++;
            }
            else{
                count = 1;
            }
        }

        prev = root;
        if(count > maxCount){
	        // count > maxCount时,要清空之前的无效结果,并更新maxCount
            ans.clear();
            ans.push_back(root->val);
            maxCount = count;
        }
        else if(count == maxCount){
            ans.push_back(root->val);
        }
        inorder(root->right, ans, count, maxCount);
    }
};
  1. 236. 二叉树的最近公共祖先

一种直观的想法是,我们遍历整棵树,并在遍历的过程中记录从根节点到目标节点的路径,递归结束后我们就得到了从根节点到p和从根节点到q的两条路径,然后我们只需要从头开始依次比较两条路径上的节点,找到不相同的节点的前一个节点,就是我们要找的答案

另外一种是在遍历时就直接处理。代码如下:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // root为空,直接返回
        if(root == NULL) return NULL;
        // root为要找的节点,直接返回
        // 对应于q是p的孩子节点的情况(或者反过来也是一样的),我们会直接返回p,然后就结束后面的递归了
        // 这是正确的,因为这种情况下答案就是p
        if(root == p || root == q) return root;

        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);

        // 要找的节点分别在当前root的左右子树中,那root就是答案
        if(left != NULL && right != NULL) return root;
        // 否则,返回不为空的那个结果
        return left == NULL ? right : left;
    }
};