1690. 石子游戏 VII
class Solution:
def stoneGameVII(self, stones: List[int]) -> int:
# 该轮次取石头后的分差 = 本轮两者 得分 的差 - 下一轮的分差 两者的共同作用使得 每一轮后的分差必定是最小的。
# 由于 每轮分差固定,所以从最终结果 往回推 结果一样。
n = len(stones)
dp = [0] * n # 最右边的石子的 下标为 j
for i in range(n - 2, -1, -1): # 剩余石头区间 stones[i]...stones[j]
total = stones[i] # 区间的求和 , 为 求 两方 本轮的分差 做准备
for j in range(i + 1, n):
total += stones[j]
dp[j] = max(total - stones[i] - dp[j], total - stones[j] - dp[j - 1]) # 拿 左边, 拿右边
return dp[-1]
# 这种 方法 好理解, 但是 在计算 区间和那里 没有 根据前缀和 求解快
class Solution {
public:
int stoneGameVII(vector<int>& stones) {
int n = stones.size();
vector<int> dp(n, 0);
for (int i = n - 2; i >= 0; --i){
int total = stones[i];
for (int j = i + 1; j < n; ++j){
total += stones[j];
dp[j] = max(total - stones[i] - dp[j], total - stones[j] - dp[j - 1]);
}
}
return dp[n - 1]; // 这里 不能用 dp[-1] 不知道为啥
}
};
看起来差不多。可能是 数据量少,才1000。 数据量大时,前缀和在 求区间和 时优势很大
方法: 前缀和 + 动态规划
class Solution:
def stoneGameVII(self, stones: List[int]) -> int:
# 该轮次取石头后的分差 = 本轮两者 得分 的差 - 下一轮的分差 两者的共同作用使得 每一轮后的分差必定是最小的。
# 由于 每轮分差固定,所以从最终结果 往回推 结果一样。
n = len(stones)
dp = [0] * n # 最右边的石子的 下标为 j
# 前缀和
s = list(accumulate(stones, initial = 0))
for i in range(n - 2, -1, -1): # 剩余石头区间 stones[i]...stones[j]
for j in range(i + 1, n):
dp[j] = max(s[j + 1] - s[i + 1] - dp[j], s[j] - s[i] - dp[j - 1]) # 拿 左边, 拿右边
return dp[-1]
class Solution {
public:
int stoneGameVII(vector<int>& stones) {
int n = stones.size();
vector<int> dp(n, 0);
// 求前缀和
vector<int> s(n + 1);
partial_sum(stones.begin(), stones.end(), s.begin() + 1);
for (int i = n - 2; i >= 0; --i){
for (int j = i + 1; j < n; ++j){
dp[j] = max(s[j + 1] - s[i + 1] - dp[j], s[j] - s[i] - dp[j - 1]);
}
}
return dp[n - 1]; // 这里 不能用 dp[-1] 不知道为啥
}
};
1686. 石子游戏 VI
class Solution:
def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:
# 拿 综合 最高的
total_value = [a + b for a, b in zip(aliceValues, bobValues)]
total_value.sort(reverse = True) # 降序
# # 所有Alice能拿到的石头的总价值,其中每个都多拿了Bob的对应石子,再减去本来就是Bob拿的石子,正好是Bob的所有石子
diff = sum(total_value[::2]) - sum(bobValues) # alice 比 bob 多的
if diff > 0:
return 1 # Alice 赢
elif diff == 0:
return 0 # 平局
else:
return -1 # Bob 赢
# 假设 排序后 a0 + b0 a1 + b1 a2 + b2 a3 + b3
# Alice a0 a2
# Bob b1 b3
# diff = ( a0 + a2 ) - (b1 + b3)
# = ( a0 + b0 + a2 + b2) - (b0 + b2 + b1 + b3) # Alice 先手拿了,对方无法再拿对应位置的。只能拿剩下位置的
class Solution {
public:
int stoneGameVI(vector<int>& aliceValues, vector<int>& bobValues) {
int n = aliceValues.size();
vector<pair<int, int>> totalvalue;
for (int i = 0; i < n; ++i){
totalvalue.emplace_back(aliceValues[i] + bobValues[i], i);
}
sort(totalvalue.rbegin(), totalvalue.rend()); // 从 大 到 小 排序
// 分别计算 价值总和
int sum_Alice = 0, sum_Bob = 0;
for (int i = 0; i < n; ++i){
if (i % 2 == 0){// Alice 先手
sum_Alice += aliceValues[totalvalue[i].second];
}else{
sum_Bob += bobValues[totalvalue[i].second];
}
}
// 比较 总和
if (sum_Alice > sum_Bob){
return 1; // Alice 赢
}else if (sum_Alice == sum_Bob){
return 0;
}else{
return -1; // Bob 赢
}
}
};