最近在写动态规划的题目,这些题目的标签都标有数学,说来也是找规律题,但是这个规律真不是正常情况下可以找到的,即使看了解析有时候也写不出来,今天难得看了点解析就自己写出来的,因此分享一下这道题的想法和题解。
废话少说,我们直接进入正题,首先要了解二叉搜索树的特点:根节点的左子树上所有节点都小于根节点,右子树上所有节点都大于根节点。然后就是找规律,以n=3为例:以1为根节点时,其余元素都大于1,左子树节点数为0,结果记为一次,右子树节点为2,在不考虑数值的话左右子树排列总数就等于n=2时候的值,即当1为根节点时结果数位arr[0]*arr[2];当2为根节点时,剩余节点一个大于2一个小于2,即左右子树各有一个节点,在不考虑值得情况下此时结果为arr[1]*arr[1];当3为根节点时,思路和1为根节点相同,只是所有节点都小于3,因此所有节点都在左子树上,右子树上的节点数为0,即结果为arr[2]*arr[0]。那么n=3能产生的不同二叉搜索树有arr[0]*arr[2]+arr[1]*arr[1]+arr[2]*arr[0]个。
由题意可计算出arr[1]=1,arr[2]=2,arr[3]=5,代码如下:
var numTrees = function (n) {let arr = new Array(n + 1).fill(0)//创建数组时创建n+1个,写的时候不会受到索引和n值差异的影响。arr[0] = 1, arr[1] = 1, arr[2] = 2, arr[3] = 5//当n=0时结果也可看成只有一次。for (let i = 4; i <= n; i++) {//从4开始向后求出其他值let m1 = 0//创建记录每个i时的总可能数for (let j = 1; j <= i; j++) {//遍历i时每一位作为根节点时候的可能let m2 =1//记录每一位作为根节点时候的可能if (j !== 1) {//当n不等于1时表示左右节点均有值m2 = arr[j - 1] * arr[i - j]} else {m2 = arr[i - j]}m1 += m2}arr[i] = m1//将i时的值赋给数组。}return arr[n]//返回最后一个值即结果。};