【Leetcode】877. Stone Game

题目地址:

https://leetcode.com/problems/stone-game/

给定一个正整数数组,设一个两人游戏,甲乙轮流走。甲可以先从数组中的两端取一个数,加到自己的分数上,同时取过的就从数组中删掉;然后乙接着从数组中的两端取,这样一直直到整个数组被取完。初始两人分数都是 0 0 0,问最后谁能获胜。题目保证平局的情况不会出现。

法1:数学。因为有偶数堆石子,所以先手必胜。具体可以参照https://blog.csdn.net/qq_46105170/article/details/104091040。代码如下:

class Solution {
 public:
  bool stoneGame(vector<int>& a) {
    return true;
  }
};

时空复杂度 O ( 1 ) O(1) O(1)

法2:动态规划。用一个整数二维数组 f [ i ] [ j ] f[i][j] f[i][j]表示在原数组只剩下 s [ i , . . . , j ] s[i,...,j] s[i,...,j]的时候,先走方能赢后手方多少分(也就是最后的先后手分差是多少)。显然如果 i = j i=j i=j,那么分差就是 s [ i ] s[i] s[i]。否则 f [ i ] [ j ] = max ⁡ { s [ i ] − f [ i + 1 ] [ j ] , s [ j ] − f [ i ] [ j − 1 ] } f[i][j]=\max\{s[i]-f[i+1][j],s[j]-f[i][j-1]\} f[i][j]=max{s[i]f[i+1][j],s[j]f[i][j1]}两种情况分别对应先手方取左端点和右端点。这样就把问题转化为规模更小的问题了。代码如下:

class Solution {
 public:
  bool stoneGame(vector<int>& a) {
    int n = a.size(), f[n][n];
    memset(f, 0, sizeof f);
    for (int len = 1; len <= n; len++)
      for (int l = 0; l + len - 1 < n; l++) {
        int r = l + len - 1;
        if (len == 1) f[l][r] = a[l];
        else f[l][r] = max(a[l] - f[l + 1][r], a[r] - f[l][r - 1]);
      }

    return f[0][n - 1] > 0;
  }
};

时空复杂度 O ( n 2 ) O(n^2) O(n2)

你可能感兴趣的:(LC,二分,位运算与数学,leetcode,动态规划,dfs,算法,c++)