動態規劃:整數拆分,你要怎麼拆?

2021-01-19 51CTO

 

整數拆分

給定一個正整數 n,將其拆分為至少兩個正整數的和,並使這些整數的乘積最大化。返回你可以獲得的最大乘積。

示例1:

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

示例 2:

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

思路

看到這道題目,都會想拆成兩個呢,還是三個呢,還是四個....

我們來看一下如何使用動規來解決。

動態規劃

動規五部曲,分析如下:

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

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

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

2.確定遞推公式

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

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

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

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

那有同學問了,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));

3.dp的初始化

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

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

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

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

這是無解的。

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

確定遍歷順序

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

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

枚舉j的時候,是從1開始的。i是從3開始,這樣dp[i - j]就是dp[2]正好可以通過我們初始化的數值求出來。

所以遍歷順序為:

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));     } } 

舉例推導dp數組

舉例當n為10 的時候,dp數組裡的數值,如下:

343.整數拆分

以上動規五部曲分析完畢,C++代碼如下:

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 - 1; j++) {                 dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));             }         }         return dp[n];     } }; 

貪心

本題也可以用貪心,每次拆成n個3,如果剩下是4,則保留4,然後相乘,但是這個結論需要數學證明其合理性!

我沒有證明,而是直接用了結論。感興趣的同學可以自己再去研究研究數學證明哈。

給出我的C++代碼如下:

class Solution { public:     int integerBreak(int n) {         if (n == 2) return 1;         if (n == 3) return 2;         if (n == 4) return 4;         int result = 1;         while (n > 4) {             result *= 3;             n -= 3;         }         result *= n;         return result;     } }; 

總結

本題掌握其動規的方法,就可以了,貪心的解法確實簡單,但需要有數學證明,如果能自圓其說也是可以的。

其實這道題目的遞推公式並不好想,而且初始化的地方也很有講究,我在寫本題的時候一開始寫的代碼是這樣的:

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

這個代碼也是可以過的!

在解釋遞推公式的時候,也可以解釋通,dp[i] 就等於 拆解i - j的最大乘積 * 拆解j的最大乘積。看起來沒毛病!

但是在解釋初始化的時候,就發現自相矛盾了,dp[1]為什麼一定是1呢?根據dp[i]的定義,dp[2]也不應該是2啊。

但如果遞歸公式是 dp[i] = max(dp[i], dp[i - j] * dp[j]);,就一定要這麼初始化。遞推公式沒毛病,但初始化解釋不通!

雖然代碼在初始位置有一個判斷if (n <= 3) return 1 * (n - 1);,保證n<=3 結果是正確的,但代碼後面又要給dp[1]賦值1 和 dp[2] 賦值 2,這其實就是自相矛盾的代碼,違背了dp[i]的定義!

我舉這個例子,其實就說做題的嚴謹性,上面這個代碼也可以AC,大體上一看好像也沒有毛病,遞推公式也說得過去,但是僅僅是恰巧過了而已。

本文轉載自微信公眾號「代碼隨想錄」,可以通過以下二維碼關注。轉載本文請聯繫代碼隨想錄公眾號。

【編輯推薦】

【責任編輯:

武曉燕

TEL:(010)68476606】

點讚 0

相關焦點

  • 關於動態規劃,你想知道的都在這裡了
    你在面試的過程中也很可能會被要求解決這樣的問題,因此,了解這項技術的重要性自然不言而喻。接下來,我將解釋什麼是動態規劃,給出一個解決動態規劃問題的秘訣,並且和大家一起分析幾個示例,以便你能夠更好地理解其應用場合和應用方法。
  • 遞歸和動態規劃
    那麼動態規劃是怎麼解決這個問題呢?答案就是「查表」。剛才我們說了遞歸是從問題的結果倒推,直到問題的規模縮小到尋常。動態規劃是從尋常入手, 逐步擴大規模到最優子結構。從剛才的兩個例子,我想大家可能對前半句話有了一定的理解,我們接下來講解下後半句。
  • 怎麼在線拆分pdf單獨提取頁面
    前段時間有位小夥伴由於經常換電腦問我怎麼在線拆分pdf文件提取出部分需要的頁面,而我告訴了她用迅捷PDF在線網站拆分pdf文件的方法,這種方法不僅支持使用電腦拆分還支持使用手機拆分。下面就來分享這種在線拆分pdf文件的方法。
  • 一套北大醫學博士總結的飛鏢拆分套路
    最近鏢姐試圖總結一套關於飛鏢比賽中的拆分攻略,無奈鏢藝不精且歸納能力不濟,只好求助網際網路。 在知乎的分享中,看到了一位來自北京大學的醫學博士的拆分策略分享,覺得十分受教,特此分享給大家! 廢話不多說,先上拆分表:
  • 動態規劃課件
    最近給別人補習算法課程時製作的動態規劃課件,分享給大家自學。
  • 解決問題的方法——拆分(分而治之)
    至少要使得能力大於問題的難度,這時問題才能被能力所解決。比如對於大人,西瓜可以拆分成較大的塊,而對於老人和孩子,拆分的塊應該小一點,這樣才更利於他們吃西瓜。在軍事學上,分散敵人的兵力,然後集中自己的兵力進行打擊,這也是拆分。《戰爭藝術概論》戰略四原則的第三條原則是:「正面突破分割敵人,然後各個擊破。」這條原則就是拆分,或者叫分而治之。
  • 人工拆牆怎麼拆最省力 拆牆注意事項有哪些
    大家都清楚,現在的購房和以往差距很大,比較早以前,房屋的交易還可以自己去進行改造,但現在如若隨意的辦理,很有可能也是會讓有些問題出現,而在於拆牆這項工作上,其實辦理還是較為容易的,當然牆在建築的時候使用了很好的工藝,所以也並非就那麼容易,那麼人工拆牆怎麼拆最省力?
  • 掌握好這些拆分手機屏幕或中框就不是件麻煩事!
    拆卸手機屏幕或中框說難不難,但講究起來卻是個實在的技術活,比如拆中框就有分冷光屏與背光屏。那麼,拆分手機屏幕或中框是件麻煩事嗎?其實並不然,掌握好手法就輕而易舉。下面從拆背光屏中框說起,需要通過加熱分離機加熱進行分離,加熱分離機溫度為80度-90度,需要注意的是,在分離背光屏時建議不使用白電油,會導致背光出現亮點。而在拆卸冷光屏中框時,同樣也需要加熱拆分,溫度依舊為80度-90度。與之不同的是,可使用白電油並用刀片輕微翹起屏幕,然後卡入OCA薄片進行拆分中框。
  • 開發商說要拆你的房子,怎麼回復才最機智?
    那麼當開發商真的說要強拆你的房子時,你知道該怎麼回復、怎麼處理嗎?「區區」開發商,沒有權力拆我的房子自2011年1月21日起,新的《國有土地上房屋徵收與補償條例》取代原來的《城市房屋拆遷管理條例》,正式開始實施。從這一天開始,新立項的拆遷項目就只能由政府作為徵收主體來主導了。
  • 又見基金主動拆分!國泰CES半導體晶片ETF 9月9日拆分
    基金主動拆分看似吃力不討好,但實際上是用短期的不便換長期的發展。 公開資料顯示,國泰CES半導體晶片ETF公告,將於9月9日拆分,9月8日(明日)是權益登記日;拆分比例為1:2。簡單一點來說,也就是明天收市後,投資者持有的基金份額到恢復正常交易的時候會翻一倍。需要指出的是,國泰CES半導體晶片ETF拆分日(9月9日)當天申購、贖回是暫停的。
  • 什麼是整數裂項,整數裂項公式方法講解
    在小學奧數中有一些非常長的整數算式,僅僅用一般的運算法則滿足不了計算要求,這時候我們要找式子中各乘式之間的規律,把各乘式裂項,前後抵消,從而簡化計算。規律和之前G老師講過的分數裂項法十分類似。原式=(1x2x3-0x1x2+2x3x4-1x2x3+3x4x5-2x3x4+……+99x100x101-98x99x100)÷3=99x100x101÷3=333300整數裂項法就是將整數乘積化成兩個乘積差的形式,這個差也不是隨便乘一個數
  • 一個複雜系統的拆分改造實踐!
    此外也要與業務方保持功能溝通、計劃溝通,確保應用拆分出來後符合使用需求、擴展需求,獲取他們的支持。2.2 定義邊界,原則:高內聚,低耦合,單一職責!業務複雜度把握後,需要開始定義各個應用的服務邊界。怎麼才算是好的邊界?像葫蘆娃兄弟一樣的應用就是好的!
  • 《速度與激情10》或拆分為上下兩部
    近日,「唐老大」範·迪塞爾接受《Total Film》雜誌採訪透露,在拍攝《速度與激情9》之前就已經開始規劃第10部大結局了。不過考慮為了回饋環球影業,也為了滿足粉絲,第10部可能拆分為兩部影片來完結。「在開拍《速度與激情9》之前,我就開始為《速度與激情10》做計劃了。」範·迪塞爾說。
  • 精裝房廚房改造一定要拆拆拆?我看你是out了!
    精裝房廚房到底要不要改?怎麼改?哪裡不需要大改,小改就能很好用?今天一起說一說。老規矩,文末總結,滑到底查看~想要擁有同款設計嗎?這樣的電線再引出來一個插座,你敢用嗎?電線質量是一方面,另一方面是由於功率問題。兩個插座串接後,允許使用的用電器功率會下降。這對硬裝大功率用電器來說,並不合適。我就想這樣拉線不行嗎?!行行行,你的房子你想幹啥都行。要從插座拉線的話,建議先換原插座裡面的電線。
  • PDF怎麼編輯?一個方法教會你拆分PDF頁面!
    既然PDF版本這麼常見,那我今天就來教大家:如何拆分PDF頁面?想要實現PDF頁面拆分,相信有很多小夥伴都不知道,其實,只要用到PDF編輯器就能實現了。要知道我們平時閱讀PDF時,用到的是PDF閱讀器,想要編輯話可不是在同一個軟體上執行的,下面就一起來看看PDF是如何編輯的,如何拆分PDF頁面!操作方法步驟:第一步、雙擊打開PDF編輯器,點擊「打開」-「瀏覽」將需要編輯的PDF打開。第二步、在軟體左側縮略圖中選中需要拆分的頁面。
  • 雅閣剎車片怎麼拆
    拆的過程中要避免輪輞刮花。用扳手結合套筒將制動鉗的螺栓拆下來,然後取下剎車皮片。由於制動鉗會有很多沙子或者泥土,所以要用抹布清除乾淨,然後塗抹消音膏,防止剎車時產生異響。雙橫臂式前懸掛、多連杆獨立後懸掛,構成完美的前後懸掛組合,在運動駕控中享受真正的動態舒適。緊湊化設計的5速自動變速器將換擋衝擊降到最低,實現了燃油經濟性和高效率的統一,並採用新的零件設計標準,提升了變速器的耐用性以及整體性能。另外,專為滿足用戶的多元化需求而設計了5速手動變速器,帶來純粹的駕駛樂趣。
  • 蘋果上市40年拆股解析:五次拆分,道指將成最大受害者
    出品 | 鳳凰網科技 鳳凰新聞客戶端 綜合整理 |簫雨、楊倩 參考來源 |wsj、reuters 在發布業績超過華爾街預期的第三財季財報和宣布拆股計劃後,盤後交易中蘋果股價首次突破400美元大關。蘋果稱公司將於8月31日按1:4的比例進行拆股,這將是其歷史上第五次拆股,最近一次是2014年,拆股比例是1:7。
  • PDF怎麼提取頁面?PDF拆分的三種方法
    怎麼提取PDF文件中的一頁或者幾頁呢?今天就來分享給大家能夠實現PDF頁面提取的三種簡易方法。方法一:軟體PDF拆分1、首先下載並安裝極速玩轉後打開軟體,選擇首頁熱門推薦中的「PDF拆分」;2、上傳PDF文檔後,在「設置拆分方式」選擇一種方式,輸入拆分點即可開始拆分;完成後,可在「轉換完成」或「轉換記錄」中找到相應的文檔點擊查看或下載均可。
  • 單詞「therein」,你能拆出多少個新的單詞?
    英語冷知識,由7個字母組成的可以多次拆分的單詞「therein(在那裡)」,在這個單詞中,你能拆分出多少個單詞?我們一起看看。07、ere三字母e,能拆分的單詞就只有一個ere,讀音:[e(r)] ,意為:在…之前。I shall be back ere nightfall. 我要在日暮之前返回。
  • 教育金應該怎麼規劃?
    我們希望孩子將來能獲得良好的教育,想要為孩子規劃教育金,想要了解下教育金相關的情況。超哥答:01教育金是超期的財務規劃如今的教育環境和我們小時候的「放養」已經大不一樣了,越來越多的爸爸媽媽關心孩子的教育,願意為孩子的教育花精力下血本,教育成本也節節攀高。