一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C++實現LeetCode(312.打氣球游戲)

C++實現LeetCode(312.打氣球游戲)

2021-12-01 14:56Grandyang C/C++

這篇文章主要介紹了C++實現LeetCode(312.打氣球游戲),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下

[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.

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

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

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 )

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

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

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

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

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

解法一:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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];
    }
};

對于題目中的例子[3, 1, 5, 8],得到的dp數組如下:

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

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

解法二:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
    }
};

到此這篇關于C++實現LeetCode(312.打氣球游戲)的文章就介紹到這了,更多相關C++實現打氣球游戲內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/grandyang/p/5006441.html

延伸 · 閱讀

精彩推薦
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
主站蜘蛛池模板: 亚洲视频在线看 | 激情小视频 | 日韩a一级欧美一级 | 天堂网在线.www天堂在线资源 | 特黄特a级特别特级特毛片 特黄a级三级三级野战 | 公交车强校花系列小说 | 国产精品久久久免费视频 | 末代皇帝无删减版在线观看 | 国产欧美日韩免费一区二区 | 夫妻性生活在线 | 99色在线视频 | 色老板免费 | 国产伦精品一区二区三区免 | 牛人国产偷窥女洗浴在线观看 | 日本中文字幕在线视频站 | 按摩师他揉我奶好爽捏我奶 | 国产一区二区精品 | 男人j放进女人的p视频免费 | 亚洲精选在线观看 | 男老头澡堂gay老头456 | 好姑娘在线视频观看免费 | 视频国产精品 | 第一次做m被调教经历 | 91免费永久国产在线观看 | 欧美日韩1区2区 | 牛牛影院成人免费网页 | 欧美成人在线影院 | 91porny新九色在线 | 国产精品露脸国语对白河北 | 亚洲视频免 | 日本wwxx护士 | 乌克兰肛交影视 | 视频免费视频观看网站 | 国产一级真人毛爱做毛片 | 2020韩国r级理论片在线观看 | 亚洲色图色 | 成人影院在线观看 | youporn在线| 国产绳艺在线播放 | 亚洲国产精品高清在线 | 91美女在线观看 |