国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹)

這篇具有很好參考價值的文章主要介紹了算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

343. 整數(shù)拆分

題目鏈接????
給定一個正整數(shù) n,將其拆分為至少兩個正整數(shù)的和,并使這些整數(shù)的乘積最大化。 返回你可以獲得的最大乘積。

示例 1:
輸入: 2
輸出: 1
解釋: 2 = 1 + 1, 1 × 1 = 1。

示例 2:
輸入: 10
輸出: 36
解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
說明: 你可以假設 n 不小于 2 且不大于 58。

思路分析

動規(guī)五部曲,分析如下:

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

dp[i]:分拆數(shù)字i,可以得到的最大乘積為dp[i]。

dp[i]的定義將貫徹整個解題過程,下面哪一步想不懂了,就想想dp[i]究竟表示的是啥!

  1. 確定遞推公式

可以想 dp[i]最大乘積是怎么得到的呢?

其實可以從1遍歷j,然后有兩種渠道得到dp[i].

一個是j * (i - j) 直接相乘。

一個是j * dp[i - j],相當于是拆分(i - j),對這個拆分不理解的話,可以回想dp數(shù)組的定義。

那有同學問了,j怎么就不拆分呢?

j是從1開始遍歷,拆分j的情況,在遍歷j的過程中其實都計算過了。那么從1遍歷j,比較(i - j) * j和dp[i - j] * j 取最大的。遞推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

也可以這么理解,j * (i - j) 是單純的把整數(shù)拆分為兩個數(shù)相乘,而j * dp[i - j]是拆分成兩個以及兩個以上的個數(shù)相乘。

如果定義dp[i - j] * dp[j] 也是默認將一個數(shù)強制拆成4份以及4份以上了。

所以遞推公式:dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});

那么在取最大值的時候,為什么還要比較dp[i]呢?

因為在遞推公式推導的過程中,每次計算dp[i],取最大的而已。

  1. dp的初始化

不少同學應該疑惑,dp[0] dp[1]應該初始化多少呢?

有的題解里會給出dp[0] = 1,dp[1] = 1的初始化,但解釋比較牽強,主要還是因為這么初始化可以把題目過了。

嚴格從dp[i]的定義來說,dp[0] dp[1] 就不應該初始化,也就是沒有意義的數(shù)值。

拆分0和拆分1的最大乘積是多少?

這是無解的。

這里我只初始化dp[2] = 1,從dp[i]的定義來說,拆分數(shù)字2,得到的最大乘積是1,這個沒有任何異議!

  1. 確定遍歷順序

確定遍歷順序,先來看看遞歸公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

dp[i] 是依靠 dp[i - j]的狀態(tài),所以遍歷i一定是從前向后遍歷,先有dp[i - j]再有dp[i]。

所以遍歷順序為:

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

注意 枚舉j的時候,是從1開始的。從0開始的話,那么讓拆分一個數(shù)拆個0,求最大乘積就沒有意義了。

j的結束條件是 j < i - 1 ,其實 j < i 也是可以的,不過可以節(jié)省一步,例如讓j = i - 1,的話,其實在 j = 1的時候,這一步就已經拆出來了,重復計算,所以 j < i - 1

至于 i是從3開始,這樣dp[i - j]就是dp[2]正好可以通過我們初始化的數(shù)值求出來。

更優(yōu)化一步,可以這樣:

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

因為拆分一個數(shù)n 使之乘積最大,那么一定是拆分成m個近似相同的子數(shù)相乘才是最大的。

例如 6 拆成 3 * 3, 10 拆成 3 * 3 * 4。 100的話 也是拆成m個近似數(shù)組的子數(shù) 相乘才是最大的。

只不過我們不知道m(xù)究竟是多少而已,但可以明確的是m一定大于等于2,既然m大于等于2,也就是 最差也應該是拆成兩個相同的 可能是最大值。

那么 j 遍歷,只需要遍歷到 n/2 就可以,后面就沒有必要遍歷了,一定不是最大值。

至于 “拆分一個數(shù)n 使之乘積最大,那么一定是拆分成m個近似相同的子數(shù)相乘才是最大的” 這個我就不去做數(shù)學證明了,感興趣的同學,可以自己證明。

  1. 舉例推導dp數(shù)組

舉例當n為10 的時候,dp數(shù)組里的數(shù)值,如下:
算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹),算法,算法,動態(tài)規(guī)劃,c++,leetcode

代碼實現(xiàn)

class Solution {
public:
    int integerBreak(int n) {
        vector<int> dp(n + 1);
        dp[2] = 1;
        for (int i = 3; i <= n ; i++) {
            for (int j = 1; j <= i / 2; j++) {
                dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
            }
        }
        return dp[n];
    }
};

96.不同的二叉搜索樹

題目鏈接????
給定一個整數(shù) n,求以 1 … n 為節(jié)點組成的二叉搜索樹有多少種?

示例:
算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹),算法,算法,動態(tài)規(guī)劃,c++,leetcode

思路分析

舉幾個例子,畫畫圖,看看有沒有什么規(guī)律,如圖:
算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹),算法,算法,動態(tài)規(guī)劃,c++,leetcode
n為1的時候有一棵樹,n為2有兩棵樹,這個是很直觀的。

算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹),算法,算法,動態(tài)規(guī)劃,c++,leetcode

來看看n為3的時候,有哪幾種情況。

當1為頭結點的時候,其右子樹有兩個節(jié)點,看這兩個節(jié)點的布局,是不是和 n 為2的時候兩棵樹的布局是一樣的?。?/p>

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

當3為頭結點的時候,其左子樹有兩個節(jié)點,看這兩個節(jié)點的布局,是不是和n為2的時候兩棵樹的布局也是一樣的?。?/p>

當2為頭結點的時候,其左右子樹都只有一個節(jié)點,布局是不是和n為1的時候只有一棵樹的布局也是一樣的??!

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

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

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

元素1為頭結點搜索樹的數(shù)量 = 右子樹有2個元素的搜索樹數(shù)量 * 左子樹有0個元素的搜索樹數(shù)量

元素2為頭結點搜索樹的數(shù)量 = 右子樹有1個元素的搜索樹數(shù)量 * 左子樹有1個元素的搜索樹數(shù)量

元素3為頭結點搜索樹的數(shù)量 = 右子樹有0個元素的搜索樹數(shù)量 * 左子樹有2個元素的搜索樹數(shù)量

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

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

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

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

如圖所示:
算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹),算法,算法,動態(tài)規(guī)劃,c++,leetcode
此時我們已經找到遞推關系了,那么可以用動規(guī)五部曲再系統(tǒng)分析一遍。

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

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

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

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

  1. 確定遞推公式

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

j相當于是頭結點的元素,從1遍歷到i為止。

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

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

初始化,只需要初始化dp[0]就可以了,推導的基礎,都是dp[0]。

那么dp[0]應該是多少呢?

從定義上來講,空節(jié)點也是一棵二叉樹,也是一棵二叉搜索樹,這是可以說得通的。

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

所以初始化dp[0] = 1

  1. 確定遍歷順序

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

那么遍歷i里面每一個數(shù)作為頭結點的狀態(tài),用j來遍歷。

代碼如下:

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= i; j++) {
        dp[i] += dp[j - 1] * dp[i - j];
    }
}
  1. 舉例推導dp數(shù)組

n為5時候的dp數(shù)組狀態(tài)如圖:
算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹),算法,算法,動態(tài)規(guī)劃,c++,leetcode
當然如果自己畫圖舉例的話,基本舉例到n為3就可以了,n為4的時候,畫圖已經比較麻煩了。

我這里列到了n為5的情況,是為了方便大家 debug代碼的時候,把dp數(shù)組打出來,看看哪里有問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-695440.html

代碼實現(xiàn)

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

到了這里,關于算法訓練day41|動態(tài)規(guī)劃 part03(LeetCode343. 整數(shù)拆分、96.不同的二叉搜索樹)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • day55 算法訓練|動態(tài)規(guī)劃part15

    day55 算法訓練|動態(tài)規(guī)劃part15

    給定字符串 s 和 t ,判斷 s 是否為 t 的子序列。 字符串的一個子序列是原始字符串刪除一些(也可以不刪除)字符而不改變剩余字符相對位置形成的新字符串。(例如,\\\"ace\\\"是\\\"abcde\\\"的一個子序列,而\\\"aec\\\"不是)。 其實就是最長公共子序列的變種題:如果公共子序列長度等于

    2024年02月02日
    瀏覽(25)
  • 代碼隨想錄第41天 | 動態(tài)規(guī)劃part03

    代碼隨想錄第41天 | 動態(tài)規(guī)劃part03

    ● 343. 整數(shù)拆分 ● 96.不同的二叉搜索樹 題目一 343. 整數(shù)拆分 給定一個正整數(shù) n,將其拆分為至少兩個正整數(shù)的和,并使這些整數(shù)的乘積最大化。 返回你可以獲得的最大乘積。 示例 : 輸入: 10 輸出: 36 解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。 說明: 你可以假設 n 不小于 2 且不大于 5

    2024年01月24日
    瀏覽(26)
  • 代碼隨想錄Day41:動態(tài)規(guī)劃Part3

    代碼隨想錄Day41:動態(tài)規(guī)劃Part3

    講解前: 毫無頭緒 講解后: 這道題的動態(tài)思路一開始很不容易想出來,雖然dp數(shù)組的定義如果知道是動態(tài)規(guī)劃的話估摸著可以想出來那就是很straight forward dp定義:一維數(shù)組dp[i], i 代表整數(shù)的值,dp[i] 代表將整數(shù) i 拆分的話可以獲得的最大乘積 然后呢就是定義遞歸推導式了,

    2024年04月27日
    瀏覽(27)
  • day44代碼訓練|動態(tài)規(guī)劃part06

    day44代碼訓練|動態(tài)規(guī)劃part06

    完全背包和01背包問題唯一不同的地方就是,每種物品有無限件 。 1. dp數(shù)組的含義 dp[i][j] 0-i物品,重量為j的容量時,最大的價值 2. 遞推公式 dp[i][j] = max(dp[i-1][j],dp[i][j-weight[i]]+value[i]); 兩種狀態(tài),不用物品i的話,直接是用dp[i-1][j] 選用物品的話,為了重復使用物品i,其實是

    2024年02月03日
    瀏覽(23)
  • LeetCode算法題解(動態(tài)規(guī)劃)|LeetCode343. 整數(shù)拆分、LeetCode96. 不同的二叉搜索樹

    LeetCode算法題解(動態(tài)規(guī)劃)|LeetCode343. 整數(shù)拆分、LeetCode96. 不同的二叉搜索樹

    題目鏈接:343. 整數(shù)拆分 題目描述: 給定一個正整數(shù)? n ?,將其拆分為? k ?個? 正整數(shù) ?的和(? k = 2 ?),并使這些整數(shù)的乘積最大化。 返回? 你可以獲得的最大乘積 ?。 示例 1: 示例?2: 提示: 2 = n = 58 算法分析: 定義dp數(shù)組及下標含義: dp[i]表述正整數(shù)i拆分成k個正整數(shù)

    2024年02月04日
    瀏覽(26)
  • 代碼隨想錄算法訓練51 | 動態(tài)規(guī)劃part12

    本題加了一個冷凍期,狀態(tài)就多了,有點難度,大家要把各個狀態(tài)分清,思路才能清晰? 視頻講解: 動態(tài)規(guī)劃來決定最佳時機,這次有冷凍期!| LeetCode:309.買賣股票的最佳時機含冷凍期_嗶哩嗶哩_bilibili 代碼隨想錄 相對122.買賣股票的最佳時機II?,本題只需要在計算賣出操

    2024年01月18日
    瀏覽(51)
  • 算法訓練day37|貪心算法 part06(LeetCode738.單調遞增的數(shù)字)

    題目鏈接???? 給定一個非負整數(shù) N,找出小于或等于 N 的最大的整數(shù),同時這個整數(shù)需要滿足其各個位數(shù)上的數(shù)字是單調遞增。 (當且僅當每個相鄰位數(shù)上的數(shù)字 x 和 y 滿足 x = y 時,我們稱這個整數(shù)是單調遞增的。) 示例 1: 輸入: N = 10 輸出: 9 示例 2: 輸入: N = 1234 輸出:

    2024年02月09日
    瀏覽(22)
  • 算法訓練day36|貪心算法 part05(重疊區(qū)間三連擊:LeetCode435. 無重疊區(qū)間763.劃分字母區(qū)間56. 合并區(qū)間)

    算法訓練day36|貪心算法 part05(重疊區(qū)間三連擊:LeetCode435. 無重疊區(qū)間763.劃分字母區(qū)間56. 合并區(qū)間)

    題目鏈接???? 給定一個區(qū)間的集合,找到需要移除區(qū)間的最小數(shù)量,使剩余區(qū)間互不重疊。 注意: 可以認為區(qū)間的終點總是大于它的起點。 區(qū)間 [1,2] 和 [2,3] 的邊界相互“接觸”,但沒有相互重疊。 示例 1: 輸入: [ [1,2], [2,3], [3,4], [1,3] ] 輸出: 1 解釋: 移除 [1,3] 后,剩下的區(qū)

    2024年02月09日
    瀏覽(94)
  • leetcode 343.整數(shù)拆分 198.打家劫舍(動態(tài)規(guī)劃)

    leetcode 343.整數(shù)拆分 198.打家劫舍(動態(tài)規(guī)劃)

    ? ?OJ鏈接 :leetcode 343.整數(shù)拆分 代碼:? OJ鏈接 :198.打家劫舍 ? ?代碼:

    2024年02月05日
    瀏覽(38)
  • 【LeetCode題目詳解】第九章 動態(tài)規(guī)劃part06 完全背的講解 518. 零錢兌換 II 377. 組合總和 Ⅳ (day44補)

    【LeetCode題目詳解】第九章 動態(tài)規(guī)劃part06 完全背的講解 518. 零錢兌換 II 377. 組合總和 Ⅳ (day44補)

    # 完全背包 有N件物品和一個最多能背重量為W的背包。第i件物品的重量是weight[i],得到的價值是value[i] 。 每件物品都有無限個(也就是可以放入背包多次) ,求解將哪些物品裝入背包里物品價值總和最大。 完全背包和01背包問題唯一不同的地方就是,每種物品有無限件 。

    2024年02月09日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包