LintCode刷题——Guess Number Game II

题目内容:

We are playing the Guess Game. The game is as follows:
I pick a number from 1 to n. You have to guess which number I picked.
Every time you guess wrong, I'll tell you whether the number I picked is higher or lower.
However, when you guess a particular number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked.

样例:

First round: You guess 5, I tell you that it's higher. You pay $5.
Second round: You guess 7, I tell you that it's higher. You pay $7.
Third round: You guess 9, I tell you that it's lower. You pay $9.

Game over. 8 is the number I picked.
You end up paying $5 + $7 + $9 = $21.

Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.
So when n = `10, return16`

算法分析:

本题大意就是给定任意一个数n, 任意给定数字i,1< i < n:

  ①如果玩家猜对数字i,则游戏结束;

  ②否则,玩家支付相应的金额 i,然后庄家告诉玩家这个数是大了还是小了,然后玩家继续猜。

本题留给我们的问题就是对于任意一个数n,玩家至少需要准备多少钱才能够保证其能够取胜。但是对于本题,我们并不知道庄家到底在1到n中挑了哪一个数,每个数均有可能成为庄家所挑选的那个数,因此我们需要对所有的挑选情况进行遍历,得出所有情况的开销,从而找到总开销最小的那种情况。那么怎么进行遍历呢?以下为主要的算法思路:

  首先我们要明确的一点就是为了带的钱确保一定能赢,所以我们假设自己的运气真的是差到家了,每次我们猜的都是猜到最后一个数我们才猜对,之前一直在付钱,因此:

  ①对于一个区间[1,n],假设我们猜 i 且没有猜对,因此我们支付金额 i 后庄家告诉我们是大了还是小了,因此眼下我们猜测的区间就缩减为[1,i-1]或者[i+1,n];

  ②无论是哪个区间,在[1,i-1]和[i+1,n]这两个区间猜数字最终都会得到一个金钱的开销,假设这两个开销已经是各自区间的最大值,因此为了确保赢,我们还是必须要考虑最差情况并选择两者中的较大者;

  ③通过①和②的分析,我们可以建立一个数组DP[i][j],i<j,其表示区间[i,j]中猜测数字时所需的最大金钱开销,因此得出动态规划表达式为DP[i][j] = min{max{DP[i][k],DP[k][j]}+k},其中 i=<k<=j;min表示所有最大开销情况中的最小值;

代码:

public class Solution {
    /*
     * @param n: An integer
     * @return: how much money you need to have to guarantee a win
     */
    int[][] DP;
    public int findSolution(int begin, int end){
        if(begin>=end){
            return 0;
        }
        if(DP[begin][end]!=0){
            return DP[begin][end];
        }
        DP[begin][end]=Integer.MAX_VALUE;
        for(int i=begin;i<=end;i++){
            int left = findSolution(begin,i-1);
            int right = findSolution(i+1,end);
            int temp = Math.max(left,right) + i;
            DP[begin][end] = Math.min(temp,DP[begin][end]);
        }
        return DP[begin][end];
    }
    public int getMoneyAmount(int n) {
        // write your code here
        DP = new int[n+1][n+1];
        int result = findSolution(1,n);
        return result;
    }
}

其中DP即为动态规划中的记忆部分,大大降低了动态规划中不必要的时间开销;

 

 

 

 

 

posted @ 2017-09-21 15:47  Revenent  阅读(424)  评论(0编辑  收藏  举报