最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++實(shí)現(xiàn)LeetCode(312.打氣球游戲)

 更新時(shí)間:2021年07月19日 14:16:44   作者:Grandyang  
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(312.打氣球游戲),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

[LeetCode] 312. Burst Balloons 打氣球游戲

Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon iyou will get nums[left] * nums[i] * nums[right]coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent.

Find the maximum coins you can collect by bursting the balloons wisely.

Note:

  • You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
  • 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

Example:

Input:

[3,1,5,8]

Output:

167

Explanation:

nums = [3,1,5,8] --> [3,5,8] -->   [3,8]   -->  [8]  --> []
coins =  3*1*5      +  3*5*8    +  1*3*8      + 1*8*1   = 167

Credits:
Special thanks to @peisi for adding this problem and creating all test cases.

這道題提出了一種打氣球的游戲,每個(gè)氣球都對(duì)應(yīng)著一個(gè)數(shù)字,每次打爆一個(gè)氣球,得到的金幣數(shù)是被打爆的氣球的數(shù)字和其兩邊的氣球上的數(shù)字相乘,如果旁邊沒有氣球了,則按1算,以此類推,求能得到的最多金幣數(shù)。參見題目中給的例子,題意并不難理解。那么大家拿到題后,總是會(huì)習(xí)慣的先去想一下暴力破解法吧,這道題的暴力搜索將相當(dāng)?shù)膹?fù)雜,因?yàn)槊看虮粋€(gè)氣球,斷開的地方又重新挨上,所有剩下的氣球又要重新遍歷,這使得分治法不能 work,整個(gè)的時(shí)間復(fù)雜度會(huì)相當(dāng)?shù)母?,不要指望可以通過 OJ。而對(duì)于像這種求極值問題,一般都要考慮用動(dòng)態(tài)規(guī)劃 Dynamic Programming 來做,維護(hù)一個(gè)二維動(dòng)態(tài)數(shù)組 dp,其中 dp[i][j] 表示打爆區(qū)間 [i,j] 中的所有氣球能得到的最多金幣。題目中說明了邊界情況,當(dāng)氣球周圍沒有氣球的時(shí)候,旁邊的數(shù)字按1算,這樣可以在原數(shù)組兩邊各填充一個(gè)1,方便于計(jì)算。這道題的最難點(diǎn)就是找狀態(tài)轉(zhuǎn)移方程,還是從定義式來看,假如區(qū)間只有一個(gè)數(shù),比如 dp[i][i],那么計(jì)算起來就很簡單,直接乘以周圍兩個(gè)數(shù)字即可更新。如果區(qū)間里有兩個(gè)數(shù)字,就要算兩次了,先打破第一個(gè)再打破了第二個(gè),或者先打破第二個(gè)再打破第一個(gè),比較兩種情況,其中較大值就是該區(qū)間的 dp 值。假如區(qū)間有三個(gè)數(shù)呢,比如 dp[1][3],怎么更新呢?如果先打破第一個(gè),剩下兩個(gè)怎么辦呢,難道還要分別再遍歷算一下嗎?這樣跟暴力搜索的方法有啥區(qū)別呢,還要 dp 數(shù)組有啥意思。所謂的狀態(tài)轉(zhuǎn)移,就是假設(shè)已知了其他狀態(tài),來推導(dǎo)現(xiàn)在的狀態(tài),現(xiàn)在是想知道 dp[1][3] 的值,那么如果先打破了氣球1,剩下了氣球2和3,若之前已經(jīng)計(jì)算了 dp[2][3] 的話,就可以使用其來更新 dp[1][3] 了,就是打破氣球1的得分加上 dp[2][3]。那假如先打破氣球2呢,只要之前計(jì)算了 dp[1][1] 和 dp[3][3],那么三者加起來就可以更新 dp[1][3]。同理,先打破氣球3,就用其得分加上 dp[1][2] 來更新 dp[1][3]。說到這里,是不是感覺豁然開朗了 ^.^

那么對(duì)于有很多數(shù)的區(qū)間 [i, j],如何來更新呢?現(xiàn)在是想知道 dp[i][j] 的值,這個(gè)區(qū)間可能比較大,但是如果知道了所有的小區(qū)間的 dp 值,然后聚沙成塔,逐步的就能推出大區(qū)間的 dp 值了。還是要遍歷這個(gè)區(qū)間內(nèi)的每個(gè)氣球,就用k來遍歷吧,k在區(qū)間 [i, j] 中,假如第k個(gè)氣球最后被打爆,那么此時(shí)區(qū)間 [i, j] 被分成了三部分,[i, k-1],[k],和 [k+1, j],只要之前更新過了 [i, k-1] 和 [k+1, j] 這兩個(gè)子區(qū)間的 dp 值,可以直接用 dp[i][k-1] 和 dp[k+1][j],那么最后被打爆的第k個(gè)氣球的得分該怎么算呢,你可能會(huì)下意識(shí)的說,就乘以周圍兩個(gè)氣球被 nums[k-1] * nums[k] * nums[k+1],但其實(shí)這樣是錯(cuò)誤的,為啥呢?dp[i][k-1] 的意義是什么呢,是打爆區(qū)間 [i, k-1] 內(nèi)所有的氣球后的最大得分,此時(shí)第 k-1 個(gè)氣球已經(jīng)不能用了,同理,第 k+1 個(gè)氣球也不能用了,相當(dāng)于區(qū)間 [i, j] 中除了第k個(gè)氣球,其他的已經(jīng)爆了,那么周圍的氣球只能是第 i-1 個(gè),和第 j+1 個(gè)了,所以得分應(yīng)為 nums[i-1] * nums[k] * nums[j+1],分析到這里,狀態(tài)轉(zhuǎn)移方程應(yīng)該已經(jīng)躍然紙上了吧,如下所示:

dp[i][j] = max(dp[i][j], nums[i - 1] * nums[k] * nums[j + 1] + dp[i][k - 1] + dp[k + 1][j])                 ( i k j )

有了狀態(tài)轉(zhuǎn)移方程了,就可以寫代碼,下面就遇到本題的第二大難點(diǎn)了,區(qū)間的遍歷順序。一般來說,遍歷所有子區(qū)間的順序都是i從0到n,然后j從i到n,然后得到的 [i, j] 就是子區(qū)間。但是這道題用這種遍歷順序就不對(duì),在前面的分析中已經(jīng)說了,這里需要先更新完所有的小區(qū)間,然后才能去更新大區(qū)間,而用這種一般的遍歷子區(qū)間的順序,會(huì)在更新完所有小區(qū)間之前就更新了大區(qū)間,從而不一定能算出正確的dp值,比如拿題目中的那個(gè)例子 [3, 1, 5, 8] 來說,一般的遍歷順序是:

[3] -> [3, 1] -> [3, 1, 5] -> [3, 1, 5, 8] -> [1] -> [1, 5] -> [1, 5, 8] -> [5] -> [5, 8] -> [8] 

顯然不是我們需要的遍歷順序,正確的順序應(yīng)該是先遍歷完所有長度為1的區(qū)間,再是長度為2的區(qū)間,再依次累加長度,直到最后才遍歷整個(gè)區(qū)間:

[3] -> [1] -> [5] -> [8] -> [3, 1] -> [1, 5] -> [5, 8] -> [3, 1, 5] -> [1, 5, 8] -> [3, 1, 5, 8]

這里其實(shí)只是更新了 dp 數(shù)組的右上三角區(qū)域,最終要返回的值存在 dp[1][n] 中,其中n是兩端添加1之前數(shù)組 nums 的個(gè)數(shù)。參見代碼如下:

解法一:

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        int n = nums.size();
        nums.insert(nums.begin(), 1);
        nums.push_back(1);
        vector<vector<int>> dp(n + 2, vector<int>(n + 2, 0));
        for (int len = 1; len <= n; ++len) {
            for (int i = 1; i <= n - len + 1; ++i) {
                int j = i + len - 1;
                for (int k = i; k <= j; ++k) {
                    dp[i][j] = max(dp[i][j], nums[i - 1] * nums[k] * nums[j + 1] + dp[i][k - 1] + dp[k + 1][j]);
                }
            }
        }
        return dp[1][n];
    }
};

對(duì)于題目中的例子[3, 1, 5, 8],得到的dp數(shù)組如下:

0    0    0    0       0     0
0    3    30  159  167  0
0    0    15  135  159  0
0    0    0    40     48   0
0    0    0    0       40   0
0    0    0    0       0     0

這題還有遞歸解法,思路都一樣,就是寫法略有不同,參見代碼如下:

解法二:

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        int n = nums.size();
        nums.insert(nums.begin(), 1);
        nums.push_back(1);
        vector<vector<int>> dp(n + 2, vector<int>(n + 2, 0));
        return burst(nums, dp, 1 , n);
    }
    int burst(vector<int>& nums, vector<vector<int>>& dp, int i, int j) {
        if (i > j) return 0;
        if (dp[i][j] > 0) return dp[i][j];
        int res = 0;
        for (int k = i; k <= j; ++k) {
            res = max(res, nums[i - 1] * nums[k] * nums[j + 1] + burst(nums, dp, i, k - 1) + burst(nums, dp, k + 1, j));
        }
        dp[i][j] = res;
        return res;
    }
};

到此這篇關(guān)于C++實(shí)現(xiàn)LeetCode(312.打氣球游戲)的文章就介紹到這了,更多相關(guān)C++實(shí)現(xiàn)打氣球游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++中左值引用,右值引用,萬能引用的關(guān)系及區(qū)別說明

    C++中左值引用,右值引用,萬能引用的關(guān)系及區(qū)別說明

    這篇文章主要介紹了C++中左值引用,右值引用,萬能引用的關(guān)系及區(qū)別說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • 使用C++調(diào)用Python代碼的方法步驟

    使用C++調(diào)用Python代碼的方法步驟

    這篇文章主要介紹了使用C++調(diào)用Python代碼的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • C語言 解決不用+、-、×、÷數(shù)字運(yùn)算符做加法的實(shí)現(xiàn)方法

    C語言 解決不用+、-、×、÷數(shù)字運(yùn)算符做加法的實(shí)現(xiàn)方法

    本篇文章是對(duì)在C語言中解決不用+、-、×、÷數(shù)字運(yùn)算符做加法的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C/C++的堆棧內(nèi)存分配的實(shí)現(xiàn)

    C/C++的堆棧內(nèi)存分配的實(shí)現(xiàn)

    內(nèi)存管理是至關(guān)重要的一個(gè)方面,堆和棧是C語言中重要的內(nèi)存分配方式,本文主要介紹了C/C++的堆棧內(nèi)存分配的實(shí)現(xiàn),詳細(xì)的介紹了這兩者在管理方式、性能和使用場景,感興趣的可以了解一下
    2024-07-07
  • C++數(shù)組去重十種方法

    C++數(shù)組去重十種方法

    數(shù)組去重是一個(gè)常見的操作,本文主要介紹了C++數(shù)組去重十種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-03-03
  • Qt實(shí)現(xiàn)自定義矩陣布局

    Qt實(shí)現(xiàn)自定義矩陣布局

    這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)自定義矩陣布局,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • linux下c語言的多線程編程

    linux下c語言的多線程編程

    這篇文章主要介紹了linux下c語言的多線程編程,需要的朋友可以參考下
    2017-10-10
  • C++容器算法示例詳解

    C++容器算法示例詳解

    在談到容器算法,我們大概率會(huì)用到謂詞predicate,謂詞返回的類型是布爾類型(bool)可以是lambda表達(dá)式、函數(shù)對(duì)象以及其它可調(diào)用的對(duì)象,這篇文章主要介紹了C++容器算法,需要的朋友可以參考下
    2024-08-08
  • 淺析設(shè)計(jì)模式中的代理模式在C++編程中的運(yùn)用

    淺析設(shè)計(jì)模式中的代理模式在C++編程中的運(yùn)用

    這篇文章主要介紹了設(shè)計(jì)模式中的代理模式在C++編程中的運(yùn)用,代理模式最大的好處就是實(shí)現(xiàn)了邏輯和實(shí)現(xiàn)的徹底解耦,需要的朋友可以參考下
    2016-03-03
  • C++單例設(shè)計(jì)模式詳細(xì)講解

    C++單例設(shè)計(jì)模式詳細(xì)講解

    單例模式(Singleton Pattern)是最簡單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式,這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建
    2022-06-06

最新評(píng)論

富阳市| 小金县| 宁河县| 华蓥市| 左权县| 墨脱县| 丹江口市| 呼伦贝尔市| 贵港市| 将乐县| 潮安县| 旬阳县| 望谟县| 芮城县| 和平区| 阿拉善右旗| 伊川县| 崇义县| 东明县| 宜兰市| 天祝| 青海省| 六枝特区| 南安市| 云林县| 洪雅县| 绵阳市| 平和县| 泾源县| 绵竹市| 台中市| 济阳县| 金塔县| 汝州市| 信宜市| 论坛| 冕宁县| 竹北市| 石景山区| 仁化县| 水城县|