LeetCode 熱題 HOT 100 Java題解——96. 不同的二叉搜尋樹

可達鴨丶發表於2020-10-16

96. 不同的二叉搜尋樹

題目:

給定一個整數 n n n,求以 1... n 1 ... n 1...n 為節點組成的二叉搜尋樹有多少種?

示例:

輸入: 3
輸出: 5
解釋:
給定 n = 3, 一共有 5 種不同結構的二叉搜尋樹:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

遞迴子問題

假設 n n n 個節點存在二叉排序樹的個數是 G ( n ) G (n) G(n),令 f ( i ) f(i) f(i) 為以 i i i 為根的二叉搜尋樹的個數,則

G ( n ) = f ( 1 ) + f ( 2 ) + f ( 3 ) + f ( 4 ) + . . . + f ( n ) G(n)=f(1)+f(2)+f(3)+f(4)+...+f(n) G(n)=f(1)+f(2)+f(3)+f(4)+...+f(n),

f ( i ) = G ( i − 1 ) ∗ G ( n − i ) f(i)=G(i−1)∗G(n−i) f(i)=G(i1)G(ni)

遞迴輕易寫出,2560ms,有時會超時

class Solution {
    public int numTrees(int n) {
        if (n == 0 || n == 1) return 1;
        int res = 0;
        for (int i = 1; i <= n; i++) {
            res += numTrees(i - 1) * numTrees(n - i);
        }
        return res;
    }
}

複雜度分析

  • 時間複雜度: O ( ? ) O(?) O(?)

    卡特蘭數複雜度。

  • 空間複雜度: O ( ? ) O(?) O(?)

    卡特蘭數複雜度。

記憶化遞迴

上述程式碼最大的問題就是太多重複計算,因此可以使用記憶化遞迴。

class Solution {
    int[] mem;
    public int recur(int n) {
        if (mem[n] != 0) return mem[n];
        int res = 0;
        for (int i = 0; i < n; i++) {
            res += recur(i) * recur(n - i - 1);
        }
        mem[n] = res;
        return res;
    }
    public int numTrees(int n) {
        if (n == 0 || n == 1) return 1;
        mem = new int[n + 1];
        mem[0] = mem[1] = 1;
        return recur(n);
    }
}

複雜度分析

  • 時間複雜度: O ( n 2 ) O(n^2) O(n2)

    與動態規劃複雜度相同。

  • 空間複雜度: O ( n ) O(n) O(n)

    需要 O ( n ) O(n) O(n)額外陣列空間。

動態規劃

d p [ 0 ] , d p [ 1 ] dp[0],dp[1] dp[0],dp[1]開始逐漸向後擴大。

public class Solution {
    public int numTrees(int n) {
        int[] dp = new int[n + 1];
        dp[0] = dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        return dp[n];
    }
}

複雜度分析

  • 時間複雜度: O ( n 2 ) O(n^2) O(n2)

    雙重迴圈。

  • 空間複雜度: O ( n ) O(n) O(n)

    需要 O ( n ) O(n) O(n)額外陣列空間。

數學方法——卡特蘭數

其實本體實質為計算卡塔蘭數 C n C_n Cn。卡塔蘭數更便於計算的定義如下:

C 0 = 1 , C n + 1 = 2 ( 2 n + 1 ) n + 2 C n C_0 = 1, \qquad C_{n+1} = \frac{2(2n+1)}{n+2}C_n C0=1,Cn+1=n+22(2n+1)Cn

public class Solution {
    public int numTrees(int n) {
        long C = 1;
        for (int i = 0; i < n; ++i) {
            C = C * 2 * (2 * i + 1) / (i + 2);
        }
        return (int) C;
    }
}

複雜度分析

  • 時間複雜度: O ( n ) O(n) O(n)

    一重迴圈。

  • 空間複雜度: O ( 1 ) O(1) O(1)

    常數級別額外空間。

相關文章