1. 程式人生 > >leetcode 375. 猜數字大小 II

leetcode 375. 猜數字大小 II

我們正在玩一個猜數遊戲,遊戲規則如下:

我從 1 到 n 之間選擇一個數字,你來猜我選了哪個數字。

每次你猜錯了,我都會告訴你,我選的數字比你的大了或者小了。

然而,當你猜了數字 x 並且猜錯了的時候,你需要支付金額為 x 的現金。直到你猜到我選的數字,你才算贏得了這個遊戲。

示例:

n = 10, 我選擇了8.

第一輪: 你猜我選擇的數字是5,我會告訴你,我的數字更大一些,然後你需要支付5塊。
第二輪: 你猜是7,我告訴你,我的數字更大一些,你支付7塊。
第三輪: 你猜是9,我告訴你,我的數字更小一些,你支付9塊。

遊戲結束。8 就是我選的數字。

你最終要支付 5 + 7 + 9 = 21 塊錢。

給定 n ≥ 1,計算你至少需要擁有多少現金才能確保你能贏得這個遊戲。

這道題一般這種猜數字的第一反映。。。。二分查詢啊,不過認真讀過之後發現,還真不是(額。。反正我拿到之後,確實首先向二分查詢的)

這道題的意思是:

輸入:5,返回6;就是,1 2 3 4 5,然後,先選4,如果小了,就確定是5,如果大了,就猜2,就可以得到答案了,4+2=6就是答案了。

具體思路,經典的動態規劃問題:

1、設定dp[len][i] 表示的意思是,長度是len的數字段,以下標為i開頭的最佳解(最小花費值)。首先初始化前兩行dp[0][i]和dp[1][0]為0,意思為,長度為0和1的數字段的花費都為0,初始化dp[2][i]為dp[2][i]=a[i]表示,以下標i開頭,長度為2的段,最佳解為a[i](比如,(2,3)這個段的最佳值為2)。

2、設定dp[len][i]:遍歷以i開頭,長度為len的所有數字,以每一個數字的位置作為切分點,切分這個段為左右兩個部分,比較左右兩個部分的值,取最大值儲存,遍歷所有數字,得到所有的切分點下的最大值,取最小值,這個值就是dp[len][i]的值,即:部分取最大,全域性取最小。動態歸化方程:

dp[len][i] = min( splitResult(j) ) (0<=j<=len);splitResult(j) = max(dp[t][i], dp[len-t-1][j+i+1])+a[j+i] (0<=t<len);

這裡j+i是遍歷小數字段時候的切分點

因此,用三重迴圈就可以了,最後一行dp[n]只有一個值,就是從dp[n][0],意思就是說從0開始長度為n的資料段的最優解,返回就行。

class Solution {
public:
    int getMoneyAmount(int n) {
        vector<vector<int> >dp(n+1, vector<int>(n+1, 0));
        vector<int> a;
        for (int i = 0; i < n; ++i) {
            a.push_back(i+1);
        }
        for (int i = 0; i < n-1; ++i) {
           dp[2][i]=a[i];
        }
        for (int len = 3; len <= n; ++len) {
            //開始求dp[3][i]
            for (int i = 0; i <= n-len; ++i) {
                //對於每個dp[3][i]都要遍歷每個值,進行且分,找到且分點的cost最小的值為dp[3][i]的值
                int global=0;
                for (int j = 0; j < len; ++j) {
                    //對於每次切分之後的兩個部分,取最大值,j是長度,從下標偏移位置為j的地方切分,左邊長度為j,右邊長度為len-j-1
                    //左邊開始的值為i,右邊開始的值為j+i+1,切分點為j+i
                    int tmp = max(dp[j][i], dp[len-j-1][j+i+1])+a[j+i];
                    //部分最大,整體最小
                    if(j==0) global = tmp;
                    else global = min(global, tmp);
                }
                dp[len][i] = global;
            }
        }
    //    for (int i = 0; i < n+1; ++i) {
    //        for (int j = 0; j < n+1; ++j) {
    //            cout<<dp[i][j]<<" ";
    //        }
    //        cout<<endl;
    //    }
        return dp[n][0];
    }
};