经典动态规划:博弈问题 :: labuladong的算法小抄 #1079
Replies: 22 comments 7 replies
-
n = piles.length |
Beta Was this translation helpful? Give feedback.
-
这也太难了吧 |
Beta Was this translation helpful? Give feedback.
-
力扣的石子游戏都到第九代了😂 |
Beta Was this translation helpful? Give feedback.
-
提供一个简单版本: class Solution:
def stoneGame(self, s: List[int]) -> bool:
n = len(s)
vstd = [[-1]*(n+1) for _ in range(n+1)]
def f(l,r):
if vstd[l][r]!=-1: return vstd[l][r]
if l==r: return s[l]
vstd[l][r] = max(s[l]-f(l+1,r),s[r]-f(l,r-1)) # 相对收益
return vstd[l][r]
return f(0,n-1)>0 |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
我想麻烦问一下东哥,dp数组在初始化为全pair(0, 0)的时候,我采取的是for-each的方式,但是明明这里是数组的引用,是有效的修改,但是为什么就是过不了?改成您的俩for初始化之后就能正常通过测试用例了... 错误实例:
|
Beta Was this translation helpful? Give feedback.
-
@Heimda 盲猜, |
Beta Was this translation helpful? Give feedback.
-
@labuladong 谢谢 东哥赐教,自己这块学的不扎实,明白啦!感谢! |
Beta Was this translation helpful? Give feedback.
-
这种DP数组的定义只能牢记了吧,写的跟艺术品似的🐮 |
Beta Was this translation helpful? Give feedback.
-
top-down 的解法更容易理解 class Solution:
def stoneGame(self, piles: List[int]) -> bool:
cache = {}
def fn(i, j):
# if there's no stones, return
if i > j:
return 0
if (i, j) in cache:
return cache[(i, j)]
# check if it's alice's turn.
# since alice picks the stone first,
# alice always picks the stone at the even position of this subarray (not the original array)
alice = True if (j - i) % 2 == 0 else False
# if it's alice's turn, then alice could pick the first or last stone
if alice:
cache[(i, j)] = max(fn(i + 1, j) + piles[i], fn(i, j - 1) + piles[j])
else:
# if it's bob's turn, then bob could pick the first or last stone
# decrease alice total score by bob's choice
cache[(i, j)] = max(fn(i + 1, j) - piles[i], fn(i, j- 1) - piles[j])
return cache[(i, j)]
return True if fn(0, len(piles) - 1) > 0 else False |
Beta Was this translation helpful? Give feedback.
-
这样也可以过,beat 100% :p
|
Beta Was this translation helpful? Give feedback.
-
东哥486题跟你所说的"更一般性的石头游戏"一样吧?不如把486题放入开头的”可解决的题目”里? |
Beta Was this translation helpful? Give feedback.
-
@nuo1nuo 感谢提醒,已添加 |
Beta Was this translation helpful? Give feedback.
-
请问这样的代码可以吗 大约速度超过30%左右 但是很好理解orz |
Beta Was this translation helpful? Give feedback.
-
去掉System.out.println()之后速度80%了 orz |
Beta Was this translation helpful? Give feedback.
-
@burushuijiaoba 打印输出是 IO 操作,很耗时的。 |
Beta Was this translation helpful? Give feedback.
-
3D tableclass Solution {
public boolean stoneGame(int[] piles) {
int size = piles.length;
int[][][] dp = new int[size][size][2];
for(int i = size-1; i >= 0; i--) {
// when only 1 pile left, 1st hand get stones only
dp[i][i][0] = piles[i];
// more than 1
for(int j = i+1; j < size; j++) {
int left = piles[i] + dp[i+1][j][1];
int right = piles[j] + dp[i][j-1][1];
if(left > right) {
dp[i][j][0] = left;
dp[i][j][1] = dp[i+1][j][0];
} else {
dp[i][j][0] = right;
dp[i][j][1] = dp[i][j-1][0];
}
}
}
return dp[0][size-1][0] >= dp[0][size-1][1];
}
} Space Compression
2D tableclass Solution {
public boolean stoneGame(int[] piles) {
int size = piles.length;
int[][] dp = new int[size][size];
for(int i = size-1; i >= 0; i--) {
// when only 1 pile left, 1st hand get stones only
dp[i][i] = piles[i];
// more than 1
for(int j = i+1; j < size; j++) {
dp[i][j] = Math.max(piles[i] - dp[i+1][j], piles[j] - dp[i][j-1]);
}
}
return dp[0][size-1] >= 0;
}
} |
Beta Was this translation helpful? Give feedback.
-
打卡,打卡 状态 i,j,轮到1号还是2号 选择:选左还是右 1号作为先手做选择后,2号是面对新(i,j)的新手。 |
Beta Was this translation helpful? Give feedback.
-
大佬,两个人足够聪明,也就是先后手有影响,还是互相独立的子问题吗?为什么可以用dp? |
Beta Was this translation helpful? Give feedback.
-
打卡,附上详细注解的Java代码 class Pair {
private int first;//先手
private int second;//后手
public Pair(int first, int second) {
this.first = first;
this.second = second;
}
}
public boolean PredictTheWinner(int[] nums) {
int n = nums.length;
//先对这个二维的dp数组进行一个声明:dp[i][j].first代表石子堆的索引为(i,j)的时候先手可以取到的最大石子数;dp[i][j].second代表石子堆的索引为(i,j)的时候后手可以取到的最大石子数
Pair[][] dp = new Pair[n][n];
//初始化,Pair数组
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
dp[i][j] = new Pair(0, 0);
}
}
//base case:如果只有一个石子堆的话,先手的最大数量就是这个石子堆的数量,后手的最大石子数量就是0
for (int i = 0; i < n; i++) {
dp[i][i].first = nums[i];
dp[i][i].second = 0;
}
//因为此时dp数组的索引和(j-1)以及(i+1)有关,所以我们从base case出发,向结果靠拢。所以从下到上,从左到右进行一个遍历
for (int i = n - 2; i >= 0; i--) {
for (int j = i + 1; j < n; j++) {
//如果先手先取左边的最大石子数,注意下次变成了后手
int left=nums[i]+dp[i+1][j].second;
//如果先手先取右边的最大石子数,注意下次变成了后手
int right=nums[j]+dp[i][j-1].second;
//因为这个人贼聪明,所以他肯定会选择取左边和取右边中最大石子数的那个
if(left>right){
//如果取左边比取右边的石子数大的话
dp[i][j].first=left;
//这一次的后手的结果就是下一次索引从(i+1,j)的先手的最大石子数
dp[i][j].second=dp[i+1][j].first;
}else{
//如果取右边比取左边的石子数大的话
dp[i][j].first=right;
//这一次的后手的结果就是下一次索引从(i,j-1)的先手的最大石子数
dp[i][j].second=dp[i][j-1].first;
}
}
}
Pair res=dp[0][n-1];
return res.first>=res.second;
} |
Beta Was this translation helpful? Give feedback.
-
东哥,dp一定是一个上三角吗?为什么用下三角去做就会出错? |
Beta Was this translation helpful? Give feedback.
-
虽然差不多记下来了,怎么从无到有想到还是太难 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
文章链接点这里:经典动态规划:博弈问题
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions