《七月集训》第二十九天 分而治之

Crazy_DM 2022-07-29 16:54:45

654.最大二叉树

解题思路:

规定一个左边界l,一个右边界r。找到[l, r]中最大值,位置为p,为其构建树节点。递归为[l, p - 1]和[p + 1, r]构建子树

class Solution {
public:
    TreeNode* create(vector<int>& nums, int l, int r) {
        if(l > r) {
            return nullptr;
        }

        int pos = 0, maxn = -1;
        for(int i = l; i <= r; ++i) {
            if(nums[i] > maxn) {
                maxn = nums[i];
                pos = i;
            }
        }

        TreeNode* root = new TreeNode(nums[pos]);
        root -> left = create(nums, l, pos - 1);
        root -> right = create(nums, pos + 1, r);
        return root;
    }
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        TreeNode* root =  create(nums, 0, nums.size() - 1);
        return root;
    }
};

1569.将子数组重新排序得到同一个二叉查找树的方案数

解题思路:

1.拿root举例,左子树大小是lsize,右子树大小是rsize。因此左子树元素排列的相对位置是固定的(在计算root时候),右子树也一样,因此我们只需要在剩余的lsize+rsize中间选出lsize大小的空间,那么左右子树的就排好了。

2.我们不难看出这是一个组合问题,有这样一条递推式C n k = C n k-1 + C n - 1 k - 1,根据递推式,我们提前建立好组合数的数组,以免需要用到的过程中还需要计算

3.由1、2可知root的方案数f(root)和左右子树大小有关,和左右子树相对位置的方案数 f(root -> left) f(root -> right)也有关,我们首先递归计算好左右子树的方案数,当左右子树为nullptr时就走到叶子节点,返回1。计算过程中若有可能越界的话需要和mod取模


class Solution {
#define mod 1000000007
#define maxn 1010
long long c[maxn][maxn];
    void insert(TreeNode* root, int val) {
        //if(root == nullptr) return ;
        if(val < root -> val) {
            if(root -> left == nullptr) {
                root -> left = new TreeNode(val);
                return ;
            }
            insert(root -> left, val);
        }
        else {
            if(root -> right == nullptr) {
                root -> right = new TreeNode(val);
                return ;
            }
            insert(root -> right, val);
        }
    }
    void print(TreeNode* root) {
        if(root == nullptr) return ;
        cout << root -> val << endl;
        print(root -> left);
        print(root -> right);
    }

    int count(TreeNode* root) {
        if(root == nullptr) return 0;
        return count(root -> left) + count(root -> right) + 1;
    }

    long long dfs(TreeNode* root) {
        if(root == nullptr) return 1;

        long long ans = dfs(root -> left) * dfs(root -> right) % mod;
        int sizeL = count(root -> left);
        int sizeR = count(root -> right);
        ans *= (c[sizeL+sizeR][sizeL] % mod); //对于左右子树而言,盘列顺序是固定的,因此只需要把左子树位置选出来,右子树就确定了
        ans %= mod;
        return ans;
    }
public:
    int numOfWays(vector<int>& nums) {
        int n = nums.size();
        for(int i = 0; i <= n; ++i) {
            for(int j = 0; j <= i; ++j) {
                if(j == 0 || j == i) c[i][j] = 1; //Cn1和Cnn
                else {
                    c[i][j] = (c[i-1][j]  + c[i-1][j-1]) % mod;
                }
            }
        }

        TreeNode* root = new TreeNode(nums[0]);
        for(int i = 1; i < n; ++i) {
            insert(root, nums[i]);
        }
        //print(root);
        return dfs(root) - 1;
    }
};

 

...全文
18 回复 打赏 收藏 举报
写回复
回复
切换为时间正序
请发表友善的回复…
发表回复
发帖
万人千题

6.2w+

社区成员

学习「 算法 」的捷径就是 「 题海战略 」,社区由「 夜深人静写算法 」作者创建,三年ACM经验,校集训队队长,亚洲区域赛金牌,世界总决赛选手。社区提供系统的训练,答疑解惑,面试经验,大厂内推等机会
社区管理员
  • 英雄哪里出来
  • Amy卜bo皮
  • Risso
加入社区
帖子事件
创建了帖子
2022-07-29 16:54
社区公告

QQ群:480072171

英雄算法交流 8 群