题目地址:
https://leetcode.com/problems/stone-game-vi/
给定共 n n n个石子, A A A和 B B B两个人轮流取石子,每个人每轮可以取任意一个石子,但同一个石子被 A A A取或被 B B B取,他们得到的分数是不同的。 A A A取得到的分数以数组 a a a表示, B B B取得到的分数以数组 b b b表示。双方都尽量对自己最优的方式玩游戏。问最后谁能赢。 A A A赢则输出 1 1 1, B B B赢则输出 − 1 -1 −1,平手则输出 0 0 0。
设 A A A的取石子方案是 ( x 0 , x 1 , . . . , x n − 1 ) (x_0,x_1,...,x_{n-1}) (x0,x1,...,xn−1), x i = 0 , 1 x_i=0,1 xi=0,1,取 1 1 1代表 A A A取该下标的石子,否则代表不取。那么 A A A与 B B B的分差就是 ∑ i = 0 n − 1 x i A [ i ] − ( 1 − x i ) B [ i ] = ∑ i = 0 n − 1 x i ( A [ i ] + B [ i ] ) − B [ i ] \sum_{i=0}^{n-1}x_iA[i]-(1-x_i)B[i]=\sum_{i=0}^{n-1}x_i(A[i]+B[i])-B[i] i=0∑n−1xiA[i]−(1−xi)B[i]=i=0∑n−1xi(A[i]+B[i])−B[i]那么 A A A要最大化这个分差,他就要取那些 A [ i ] + B [ i ] A[i]+B[i] A[i]+B[i]尽可能大的石子,所以 A A A的最优方案就是先取 A [ i ] + B [ i ] A[i]+B[i] A[i]+B[i]最大的石子,类似的, B B B的最大方案就是剩余石子里分数和最大的。所以要判断 A A A是否能赢,就模拟这个取石子过程最后看谁得分高就行。代码如下:
class Solution {
public:
int stoneGameVI(vector<int>& as, vector<int>& bs) {
int n = as.size();
vector<vector<int>> ps(n, vector<int>(2, 0));
for (int i = 0; i < n; i++) ps[i][0] = as[i], ps[i][1] = bs[i];
sort(ps.begin(), ps.end(), [](auto &p1, auto &p2) {
return p1[0] + p1[1] > p2[0] + p2[1];
});
int ascore = 0, bscore = 0;
for (int i = 0; i < n; i++)
i % 2 == 0 ? ascore += ps[i][0] : bscore += ps[i][1];
return ascore == bscore ? 0 : ascore < bscore ? -1 : 1;
}
};
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)。