leetcode:不同的二叉搜索樹

題目來源:力扣

題目介紹:

給定一個整數 n,求以 1 … n 爲節點組成的二叉搜索樹有多少種?
示例:
輸入: 3
輸出: 5
解釋:
給定 n = 3, 一共有 5 種不同結構的二叉搜索樹.

審題:

考慮對於從iijj的節點序列,我們可以選擇iijj的任意一個值作爲二叉搜索樹根節點,假設選擇kk作爲根節點,則此時左子樹的有節點序列iik1k-1構成,右子樹由節點k+1k+1jj構成.假設我們節點序列iik1k-1共有mm種不同形式的二叉搜索樹形式,節點序列k+1k+1jj共有nn種不同形式的二叉搜索樹,則我們選擇kk作爲根節點,可以得到mnmn種不同的二叉搜索樹形式.而節點序列iijj可能構成的二叉搜索樹個數選擇不同根節點kk得到的二叉樹個數之和.

事實上,我們可以發現,該問題並不涉及最優性問題,因爲爲了計算所有可能的二叉樹種類,我們需要計算每一個可能的根節點位置選擇方案下,所可能產生的二叉搜索樹個數,在這一步中,並不存在最優選擇,而是將所有選擇結果相加.但由於子問題存在重疊,因此我們仍然可以考慮使用動態規劃算法解決該問題.

爲了求解長度爲kk的節點序列可能產生的二叉搜索樹總個數,我們需要已知所有長度小於kk的節點序列所可能產生的二叉搜索樹個數,此時的基礎情形便是長度爲1或長度爲0的情形.如果當前節點序列長度爲0或1,則此時的二叉搜索樹只有一種形式.
我們使用二維數組存儲每一狀態下,總方案.在該問題中,狀態包括節點序列的起點與終點S[i[j]S[i[j]表示節點序列i,i+1,...j1i, i+1, ...j-1所能構長的二叉搜索樹個數.

以上是我一開始面對該問題時所提出的方法, 後面我進一步思考發現,二叉搜索樹的可能個數與當前節點序列的值並無關係,僅與當前節點序列的長度有關.因此,我們可以進一步簡化動態規劃算法. 此時,當前的狀態變量爲節點序列的長度ll, 我們可以在每一步選擇左子樹的大小,其取值範圍從00l1l-1. 我們使用一維數組S存儲當前狀態下二叉搜索樹可能個數, 我們可以得到如下狀態轉移方程:
S[l]=sum{S[left]+S[lleft1],0leftl1}S[l] = sum\{S[left] + S[l-left-1] , 0 \leq left \leq l-1 \}

java算法:

方法一
class Solution {
    public int numTrees(int n) {
        //S[i][j]表示以i...j-1爲節點組成的二叉搜索樹共有多少種
        //如果根節點選爲k, 則S[i][k] + S[k+1][j]

        int[][] S = new int[n+2][n+3];

        //basecase
        for(int i = 1; i < n+2; i++){
            S[i][i] = 1;
            S[i][i+1] = 1;
        }

        //如果計算長度爲k的節點所能組成的二叉樹, 我們應當計算確定所有長度小於k的節點序列所能組成的二叉樹

        for(int len = 2; len <= n; len++){
            for(int left = 1; left <= n-len+1; left++ ){
                int right = left+len;
                int total = 0;
                for(int root = left; root < right; root++){
                    total += (S[left][root] * S[root+1][right]);
                }
                S[left][right] = total;
            }
        }
        return S[1][n+1];
    }
}
方法二:
class Solution {
    public int numTrees(int n) {

        int[] S = new int[n+1];

        S[0] = 1;
        S[1] = 1;

        //如果計算長度爲k的節點所能組成的二叉樹, 我們應當計算確定所有長度小於k的節點序列所能組成的二叉樹

        for(int len = 2; len <= n; len++){
            int total = 0;
            for(int leftSize = 0; leftSize < len; leftSize++){
                total += S[leftSize] * S[len-leftSize-1];
            }
            S[len] = total;
        }
        return S[n];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章