自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

DP入門(mén)之不同的二叉搜索樹(shù)!

開(kāi)發(fā) 前端
關(guān)于什么是二叉搜索樹(shù),我們之前在講解二叉樹(shù)專題的時(shí)候已經(jīng)詳細(xì)講解過(guò)了,也可以看看這篇二叉樹(shù):二叉搜索樹(shù)登場(chǎng)!再回顧一波。

不同的二叉搜索樹(shù)

題目鏈接:https://leetcode-cn.com/problems/unique-binary-search-trees

給定一個(gè)整數(shù) n,求以 1 ... n 為節(jié)點(diǎn)組成的二叉搜索樹(shù)有多少種?

示例:

思路

這道題目描述很簡(jiǎn)短,但估計(jì)大部分同學(xué)看完都是懵懵的狀態(tài),這得怎么統(tǒng)計(jì)呢?

關(guān)于什么是二叉搜索樹(shù),我們之前在講解二叉樹(shù)專題的時(shí)候已經(jīng)詳細(xì)講解過(guò)了,也可以看看這篇二叉樹(shù):二叉搜索樹(shù)登場(chǎng)!再回顧一波。

了解了二叉搜索樹(shù)之后,我們應(yīng)該先舉幾個(gè)例子,畫(huà)畫(huà)圖,看看有沒(méi)有什么規(guī)律,如圖:

不同的二叉搜索樹(shù)

n為1的時(shí)候有一棵樹(shù),n為2有兩棵樹(shù),這個(gè)是很直觀的。

不同的二叉搜索樹(shù)1

來(lái)看看n為3的時(shí)候,有哪幾種情況。

當(dāng)1為頭結(jié)點(diǎn)的時(shí)候,其右子樹(shù)有兩個(gè)節(jié)點(diǎn),看這兩個(gè)節(jié)點(diǎn)的布局,是不是和 n 為2的時(shí)候兩棵樹(shù)的布局是一樣的啊!

(可能有同學(xué)問(wèn)了,這布局不一樣啊,節(jié)點(diǎn)數(shù)值都不一樣。別忘了我們就是求不同樹(shù)的數(shù)量,并不用把搜索樹(shù)都列出來(lái),所以不用關(guān)心其具體數(shù)值的差異)

當(dāng)3為頭結(jié)點(diǎn)的時(shí)候,其左子樹(shù)有兩個(gè)節(jié)點(diǎn),看這兩個(gè)節(jié)點(diǎn)的布局,是不是和n為2的時(shí)候兩棵樹(shù)的布局也是一樣的啊!

當(dāng)2為頭結(jié)點(diǎn)的時(shí)候,其左右子樹(shù)都只有一個(gè)節(jié)點(diǎn),布局是不是和n為1的時(shí)候只有一棵樹(shù)的布局也是一樣的啊!

發(fā)現(xiàn)到這里,其實(shí)我們就找到了重疊子問(wèn)題了,其實(shí)也就是發(fā)現(xiàn)可以通過(guò)dp[1] 和 dp[2] 來(lái)推導(dǎo)出來(lái)dp[3]的某種方式。

思考到這里,這道題目就有眉目了。

dp[3],就是 元素1為頭結(jié)點(diǎn)搜索樹(shù)的數(shù)量 + 元素2為頭結(jié)點(diǎn)搜索樹(shù)的數(shù)量 + 元素3為頭結(jié)點(diǎn)搜索樹(shù)的數(shù)量

元素1為頭結(jié)點(diǎn)搜索樹(shù)的數(shù)量 = 右子樹(shù)有2個(gè)元素的搜索樹(shù)數(shù)量 * 左子樹(shù)有0個(gè)元素的搜索樹(shù)數(shù)量

元素2為頭結(jié)點(diǎn)搜索樹(shù)的數(shù)量 = 右子樹(shù)有1個(gè)元素的搜索樹(shù)數(shù)量 * 左子樹(shù)有1個(gè)元素的搜索樹(shù)數(shù)量

元素3為頭結(jié)點(diǎn)搜索樹(shù)的數(shù)量 = 右子樹(shù)有0個(gè)元素的搜索樹(shù)數(shù)量 * 左子樹(shù)有2個(gè)元素的搜索樹(shù)數(shù)量

有2個(gè)元素的搜索樹(shù)數(shù)量就是dp[2]。

有1個(gè)元素的搜索樹(shù)數(shù)量就是dp[1]。

有0個(gè)元素的搜索樹(shù)數(shù)量就是dp[0]。

所以dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2]

如圖所示:

不同的二叉搜索樹(shù)2

此時(shí)我們已經(jīng)找到遞推關(guān)系了,那么可以用動(dòng)規(guī)五部曲再系統(tǒng)分析一遍。

1.確定dp數(shù)組(dp table)以及下標(biāo)的含義

dp[i] :1到i為節(jié)點(diǎn)組成的二叉搜索樹(shù)的個(gè)數(shù)為dp[i]。

也可以理解是i的不同元素節(jié)點(diǎn)組成的二叉搜索樹(shù)的個(gè)數(shù)為dp[i] ,都是一樣的。

以下分析如果想不清楚,就來(lái)回想一下dp[i]的定義

2.確定遞推公式

在上面的分析中,其實(shí)已經(jīng)看出其遞推關(guān)系, dp[i] += dp[以j為頭結(jié)點(diǎn)左子樹(shù)節(jié)點(diǎn)數(shù)量] * dp[以j為頭結(jié)點(diǎn)右子樹(shù)節(jié)點(diǎn)數(shù)量]

j相當(dāng)于是頭結(jié)點(diǎn)的元素,從1遍歷到i為止。

所以遞推公式:dp[i] += dp[j - 1] * dp[i - j]; ,j-1 為j為頭結(jié)點(diǎn)左子樹(shù)節(jié)點(diǎn)數(shù)量,i-j 為以j為頭結(jié)點(diǎn)右子樹(shù)節(jié)點(diǎn)數(shù)量

3.dp數(shù)組如何初始化

初始化,只需要初始化dp[0]就可以了,推導(dǎo)的基礎(chǔ),都是dp[0]。

那么dp[0]應(yīng)該是多少呢?

從定義上來(lái)講,空節(jié)點(diǎn)也是一棵二叉樹(shù),也是一棵二叉搜索樹(shù),這是可以說(shuō)得通的。

從遞歸公式上來(lái)講,dp[以j為頭結(jié)點(diǎn)左子樹(shù)節(jié)點(diǎn)數(shù)量] * dp[以j為頭結(jié)點(diǎn)右子樹(shù)節(jié)點(diǎn)數(shù)量] 中以j為頭結(jié)點(diǎn)左子樹(shù)節(jié)點(diǎn)數(shù)量為0,也需要dp[以j為頭結(jié)點(diǎn)左子樹(shù)節(jié)點(diǎn)數(shù)量] = 1, 否則乘法的結(jié)果就都變成0了。

所以初始化dp[0] = 1

4.確定遍歷順序

首先一定是遍歷節(jié)點(diǎn)數(shù),從遞歸公式:dp[i] += dp[j - 1] * dp[i - j]可以看出,節(jié)點(diǎn)數(shù)為i的狀態(tài)是依靠 i之前節(jié)點(diǎn)數(shù)的狀態(tài)。

那么遍歷i里面每一個(gè)數(shù)作為頭結(jié)點(diǎn)的狀態(tài),用j來(lái)遍歷。

代碼如下:

  1. for (int i = 1; i <= n; i++) { 
  2.     for (int j = 1; j <= i; j++) { 
  3.         dp[i] += dp[j - 1] * dp[i - j]; 
  4.     } 

5.舉例推導(dǎo)dp數(shù)組

n為5時(shí)候的dp數(shù)組狀態(tài)如圖:

不同的二叉搜索樹(shù)3

當(dāng)然如果自己畫(huà)圖舉例的話,基本舉例到n為3就可以了,n為4的時(shí)候,畫(huà)圖已經(jīng)比較麻煩了。

我這里列到了n為5的情況,是為了方便大家 debug代碼的時(shí)候,把dp數(shù)組打出來(lái),看看哪里有問(wèn)題。

綜上分析完畢,C++代碼如下:

  1. class Solution { 
  2. public
  3.     int numTrees(int n) { 
  4.         vector<int> dp(n + 1); 
  5.         dp[0] = 1; 
  6.         for (int i = 1; i <= n; i++) { 
  7.             for (int j = 1; j <= i; j++) { 
  8.                 dp[i] += dp[j - 1] * dp[i - j]; 
  9.             } 
  10.         } 
  11.         return dp[n]; 
  12.     } 
  13. }; 
  • 時(shí)間復(fù)雜度:
  • 空間復(fù)雜度:

大家應(yīng)該發(fā)現(xiàn)了,我們分析了這么多,最后代碼卻如此簡(jiǎn)單!

總結(jié)

這道題目雖然在力扣上標(biāo)記是中等難度,但可以算是困難了!

首先這道題想到用動(dòng)規(guī)的方法來(lái)解決,就不太好想,需要舉例,畫(huà)圖,分析,才能找到遞推的關(guān)系。

然后難點(diǎn)就是確定遞推公式了,如果把遞推公式想清楚了,遍歷順序和初始化,就是自然而然的事情了。

可以看出我依然還是用動(dòng)規(guī)五部曲來(lái)進(jìn)行分析,會(huì)把題目的方方面面都覆蓋到!

而且具體這五部分析是我自己平時(shí)總結(jié)的經(jīng)驗(yàn),找不出來(lái)第二個(gè)的,可能過(guò)一陣子 其他題解也會(huì)有動(dòng)規(guī)五部曲了,哈哈。

當(dāng)時(shí)我在用動(dòng)規(guī)五部曲講解斐波那契的時(shí)候,一些錄友和我反應(yīng),感覺(jué)講復(fù)雜了。

其實(shí)當(dāng)時(shí)我一直強(qiáng)調(diào)簡(jiǎn)單題是用來(lái)練習(xí)方法論的,并不能因?yàn)楹?jiǎn)單我就代碼一甩,簡(jiǎn)單解釋一下就完事了。

可能當(dāng)時(shí)一些同學(xué)不理解,現(xiàn)在大家應(yīng)該感受方法論的重要性了,加油??

本文轉(zhuǎn)載自微信公眾號(hào)「代碼隨想錄」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系代碼隨想錄公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: 代碼隨想錄
相關(guān)推薦

2021-08-31 11:35:24

二叉搜索樹(shù)迭代法公共祖先

2022-12-26 00:51:33

雙向鏈表二叉搜索樹(shù)

2021-09-02 11:31:28

二叉搜索樹(shù)迭代法公共祖先

2021-09-03 08:58:00

二叉搜索樹(shù)節(jié)點(diǎn)

2021-10-11 06:38:52

遞歸二叉搜索樹(shù)

2021-12-07 06:55:17

二叉搜索樹(shù)鏈表

2020-04-27 07:05:58

二叉樹(shù)左子樹(shù)右子樹(shù)

2021-08-26 11:31:11

二叉樹(shù)數(shù)據(jù)結(jié)構(gòu)算法

2024-01-17 07:36:50

二叉搜索聯(lián)系簿

2023-07-31 08:01:13

二叉搜索測(cè)試

2023-02-13 08:02:08

哈希函數(shù)哈希表搜索樹(shù)

2021-04-28 20:12:27

數(shù)據(jù)結(jié)構(gòu)創(chuàng)建

2021-03-22 08:23:29

LeetCode二叉樹(shù)節(jié)點(diǎn)

2021-09-07 11:01:41

二叉搜索樹(shù)序數(shù)組

2020-12-11 09:49:29

二叉樹(shù)搜索樹(shù)數(shù)據(jù)

2021-04-06 08:20:24

二叉搜索樹(shù)數(shù)據(jù)結(jié)構(gòu)算法

2021-04-19 07:47:42

數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)Tree

2021-04-20 08:37:14

數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)樹(shù)

2021-09-06 10:38:50

二叉搜索樹(shù)遞歸

2020-10-11 16:56:48

二叉搜索樹(shù)代碼開(kāi)發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)