1. 程式人生 > >題目一:給出一個n,代表有從1到n的數字[1,2,3,··· n],問可以構成多少種二叉搜索樹?

題目一:給出一個n,代表有從1到n的數字[1,2,3,··· n],問可以構成多少種二叉搜索樹?

pri int private 計算 stat 題目 二叉搜索樹 得到 pre

題目一:給出一個n,代表有從1到n的數字[1,2,3,··· n],問可以構成多少種二叉搜索樹?

一開始的想法是直接遞歸構造,時間復雜度是指數上升;
後來想法是找規律:
先看例子:

n = 1, 有一個元素,可以構成一個二叉搜索樹,左右都沒有元素,總數量 = 左子樹數量 右子樹數量,記為f(1) = f(0) f(0) = 1,這兒可以將f(0)初始化為1;
n = 2, 1做根,那麽左子樹沒有元素記為f(0),右子樹有一個元素記為f(1), 2做根,左子樹有一個元素,記為f(1),右子樹沒有元素記為f(0);
總共:f(2) = f(0) f(1) + f(1) f(0) = 2;
n = 3, 1做根,數量 = f(0) f(2), 2做根 數量 = f(1) f(1), 3做根, 數量 = f(2) f(0);
總共 f(3) = f(0) f(2) + f(1) f(1) + f(2) f(0) = 5;
可以看出f(n),依賴與f(0)到f(n-1),換句話說可以有前面的n-1項推導出第n項;
分析關系表達式:
記h(k)為以k為根可以生成的二叉搜索樹數量;
當以k為根時,他的左子樹為[1,2 ··· k-1]構成,也就是左子樹有k-1個元素構成,這個就可以記為f(k-1);
右子樹為[k+1 ··· n]構成,也就是右子樹有n-k個元素構成,這個可以記為f(n-k);
那麽h(k) = f(k-1) * f(n-k); 要記得k的範圍可以從1到n;
整合以上規律可得到:有n個元素的二叉搜索樹的數量;f(n) = h(1)+h(2)+···+h(n) = ∑ h(k) ,0 < k <= n;
又因為h(k) = f(k-1) f(n-k)得到:f(n) = ∑ f(k-1) f(n-k); 0 < k <= n;
代碼:輸入n,輸出可以構造出的二叉搜索樹的數量;
時間復雜度O(n^3);

private static int BSCount(int n) {
		int[] res = new int[n+1];
		res[0] = 1;
		for(int i = 1; i<=n; i++) {
			for(int k=1; k<=i; k++) {
				res[i] += res[k-1] * res[i-k];
//				System.out.println(i + " k:" + k +" " + res[i]);
			}
		}
		return res[res.length-1];
	}

  註釋:第一個循環用來控制根節點肯能出現的情況。因為這是一個遞歸表達式,第二個循環是用來控制計算以當下值為根節點的時候,所以依賴的前面表達式的值是多少。

      比如計算以當n3的時候,需要計算一下三種情況:

          res[3]+=res[0]*res[2]  (以1為根節點時)

          res[3]+=res[1]*res[1]  (以2為根節點時)

          res[3]+=res[2]*res[0]  (以3為根節點時)

      那麽,這些表達式中的res[1]和res[2]需要提前計算。這個是由第二個循環來完成的。

題目一:給出一個n,代表有從1到n的數字[1,2,3,··· n],問可以構成多少種二叉搜索樹?