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

题目

核心思路

这道题最主要的就是理解二叉搜索树(BST)的插入原理,然后就要通过数学计算排列组合可能了,直接上图解分析即可。


根据二叉搜索树(BST)的定义,以及插入过程,可以发现,第一个元素作为根节点,必须是确定不变的,又因为二叉搜索树规定了其左边元素均小于它本身,它右边元素均大于它本身,也就是说,确定根节点后,左子树有哪些结点、右子树有哪些结点都确定了,既然如此,我们可以将除了根节点以外的结点分为:左子树的结点与右子树的结点 两类,这样两类结点就相互独立互不影响了,左子树和右子树之间的顺序可以任意交叉(PS:如果来了一个结点属于左子树,那么他肯定不会插入到右子树,故不会相互影响 )
所以,所有的可能种数就是:左右子树间的排列 * 左子树的可能性 * 右子树的可能性,而 左子树的可能性右子树的可能性 恰好是原问题的子问题,所以把他交给递归处理即可,需要解决的就是 左右子树间的排列

参考上例,除了根节点剩余4个结点,左右子树间互不影响所以可以把左子树看成L结点,右子树看成R结点,他们的排列也就是总共四个位置,选出2个位置来放L结点,剩下2个位置来放R结点即可:C₄² = 6 (也就是相当于下标为n - 1,上标为比根节点小的结点个数)
综上,只要我们提前求出范围内的组合数(使用杨辉三角递推),然后递归计算即可。

完整代码

class Solution {

    private int[][] C;// 存储组合数
    private final int MOD = (int) 1e9 + 7;

    public int numOfWays(int[] nums) {
        int n = nums.length;
        C = new int[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                if (j == 0) {
                    C[i][j] = 1;
                } else {
                    C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
                }
            }
        }

        return (f(nums) + MOD - 1) % MOD;
    }

    private int f(int[] nums) {
        if (nums == null || nums.length == 0)
            return 1;
        int n = nums.length;
        int k = nums[0];
        int[] left = new int[k - 1], right = new int[n - k];// 左右子数组
        int li = 0, ri = 0;// 左右数组下标
        for (int i = 1; i < n; i++) {
            if (nums[i] > k) {
                right[ri++] = nums[i] - k;// 将数据按原大小和顺序与下标对齐
            } else {
                left[li++] = nums[i];
            }
        }

        return (int) ((long) C[n - 1][k - 1] * f(left) % MOD * f(right) % MOD);
    }
}

这里有三个需要注意的细节

  • 在给定范围内,组合数是可能超过数据范围的,所以可以提前使它对MOD取模,保证数据在int范围内
  • 在使用组合数的时候,第一次乘上f(left也有可能越界,所以事先强转为long保证数据的正确性。
  • 由于使用组合数C[n - 1][k - 1]时,比k小的数选用 k - 1 ,也就是认为每个nums都是从1到n的,所以可以在更新右子树数组时将元素与下标对齐(nums[i] - k)
    剩下的内容就是交给递归,靠递归来分割左子树和右子树计算结果即可。

总结

又是一道数学题,唉,高中我还挺喜欢数学的,可上了大学就越来越不行了,做题时候也是好多一般性的问题找不到突破点,只能一点点学习学习这样的思路了。
如果文章有写的不正确的地方还请指出。感恩相遇~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348