一、Problem
亚历克斯和李继续他们的石子游戏。许多堆石子 排成一行,每堆都有正整数颗石子 piles[i]。游戏以谁手中的石子最多来决出胜负。
亚历克斯和李轮流进行,亚历克斯先开始。最初,M = 1。
在每个玩家的回合中,该玩家可以拿走剩下的 前 X 堆的所有石子,其中 1 <= X <= 2M。然后,令 M = max(M, X)。
游戏一直持续到所有石子都被拿走。
假设亚历克斯和李都发挥出最佳水平,返回亚历克斯可以得到的最大数量的石头。
输入:piles = [2,7,9,4,4]
输出:10
解释:
如果亚历克斯在开始时拿走一堆石子,李拿走两堆,接着亚历克斯也拿走两堆。在这种情况下,亚历克斯可以拿到 2 + 4 + 4 = 10 颗石子。
如果亚历克斯在开始时拿走两堆石子,那么李就可以拿走剩下全部三堆石子。在这种情况下,亚历克斯可以拿到 2 + 7 = 9 颗石子。
所以我们返回更大的 10。
提示:
1 <= piles.length <= 100
1 <= piles[i] <= 10 ^ 4
二、Solution
方法一:记忆化
记忆化也可以用 dp 的角度来分析
- 定义状态:
- 表示当前取到第 堆且最多可以取 堆时的最大得分
- 思考初始化:
- 思考状态转移方程:
这里要注意的是:我们是不知道如何状态转移才能让压力克斯有最大得分,但我们唯一可以确定的就是压力克斯可以取的堆数 X,而知道 X 后,李开始取石子的起始位置也就确定了,所以我们只能枚举所有可取到的堆数 X,然后从中选最优
class Solution {
int n, s[], f[][];
int dfs(int i, int m) {
if (i >= n)
return 0;
if (i + 2*m >= n)
return s[i];
if (f[i][m] != 0)
return f[i][m];
int max = 0;
for (int x = 1; x <= 2*m; x++) {
max = Math.max(max, s[i] - dfs(i+x, Math.max(x, m)));
}
return f[i][m] = max;
}
public int stoneGameII(int[] piles) {
n = piles.length;
s = new int[n+1];
f = new int[n][n+100];
for (int i = n-1; i >= 0; i--)
s[i] = s[i+1] + piles[i];
return dfs(0, 1);
}
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:dp
代办…
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,