问题解释
题目乍一看我是没有看懂的,遇到不太明白的题意或是不能一眼看出如何解决的题目,可以举几个具体的例子,尝试去找规律,这道题就是如此。
当n=1时,花费最小应该为0;
当n=2时,花费最小应该尝试取1;
当n=3时,花费最小应该尝试取2;
当n=4时,因为此时不能一眼看出来,我们就分类讨论,先取1、先取2、…,到这里细心的你一定发现了子问题的存在,例如取3,那么子问题就是去解决n=2。最后结果花费最小应该尝试取1和3;
当n=5时,同n=4处理方法类似,最终花费最小应该尝试取2和4;
那么现在我们可以用另外一句直观的话表达题目的意思。我们需要消耗最少的money找到所有元素所在的位置,且每次如果猜测错误,会提示高了或者低了,即只会发生其一(存在最大值问题)。为什么是所有元素的位置?因为picked值不知道,而我们需要win,所以必须考虑所有可能的picked,即所有元素。
DP解决
我们在上面的讨论中已经看到了子问题的影子,当我们增大n,比如取10,那么子问题就更加明显了,例如假设我们先尝试取5,因为我们不知道picked的元素是什么,所以还需要分别求n=[1,4]和n=[6,10]区间找到每个元素位置耗费的最小money,这就是子问题。正如前面所述,取5后会提示过高或过低,那么我们只需要两个子区间最小耗费中的较大值作为取5时耗费的最小money,又因为最小耗费不一定初始取5,所以需要像5这样讨论1-10中的每一个元素。
初始状态很容易想到就是长度为1和长度为2的区间,长度为1,耗费0,长度为2耗费第一个元素值。状态转移方程如下:
M
i
n
C
o
s
t
(
i
,
j
)
=
m
i
n
{
m
+
m
a
x
(
M
i
n
C
o
s
t
(
i
,
m
−
1
)
,
M
i
n
C
o
s
t
(
m
+
1
,
j
)
)
,
m
∈
[
i
,
j
]
}
MinCost(i,j) = min\{m+max(MinCost(i,m-1),MinCost(m+1,j)),m\in\ [i,j]\}
MinCost(i,j)=min{m+max(MinCost(i,m−1),MinCost(m+1,j)),m∈ [i,j]}
M
i
n
C
o
s
t
(
i
,
j
)
MinCost(i,j)
MinCost(i,j)表示在区间
[
i
,
j
]
[i,j]
[i,j]中找到区间中每个元素位置耗费的最小money。
代码
class Solution {
public:
int getMoneyAmount(int n) {
int arr[n + 1][n + 1];
memset(arr, 0, (n+1)*(n+1)*sizeof(int));
for(int i = 1; i < n;i++)
{
arr[i][i+1] = i;
}
for(int interval = 2; interval < n; interval++)
{
for(int i = 1; i <= n - interval; i++)
{
int m = min(i+arr[i+1][i+interval],i+interval+arr[i][i+interval-1]);
for(int j = i+1; j <= i+interval-1; j++)
{
int temp = j+max(arr[i][j-1],arr[j+1][i+interval]);
if(temp < m)
m = temp;
}
arr[i][i+interval] = m;
}
}
return arr[1][n];
}
};
打赏博主