您的位置:首页 > 理论基础 > 数据结构算法

数据结构和算法经典100题-第22题

2015-12-16 22:17 513 查看
题目要求:

排成一条线的纸牌博弈问题

给定一个整形数组arr,代表数值不同的纸牌排成一条线。玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿,但每个玩家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪明,请返回最后获胜者的分数。

解题分析:

假设数组int arr
,设函数f(i,j)表示数列a[i…j]序列被“先手拿”最终得分;假设g(i,j)表示数列a[i…j]序列“后手拿”最终得分。

分析可知f(i,j) = max{g(i+1,j)+arr[i], g(i,j-1)+arr[j]};

g(i,j) = min{f(i+1,j), f(i,j-1)}; (说明:因为双方都绝顶聪明,所以假设A先手,B后手,A一定把两种情况中小的留给后手选手)

在分析完题目后,我们发现这是一个递归问题,可以暴力递归直接解这个问题,代码如下:

class Game {
public:
Game(std::vector<int> &ivecArray) : m_ivecArr(ivecArray) {};
~Game() {};
int getScore();
int f(int i, int j);
int g(int i, int j);
private:
std::vector<int> &m_ivecArr;
};

int Game::f(int i, int j) {
if (i == j) {
return m_ivecArr[i];
}

return max<int>( (m_ivecArr[i] + g(i+1, j)), (m_ivecArr[j] + g(i, j-1)) );
}

int Game::g(int i, int j) {
if (i == j) {
return 0;
}

return min<int>( f(i+1, j),  g(i, j-1) );
}

int Game::getScore() {
if (ivecArr.empty()) {
return 0;
}

return max<int>(f(0,(ivecArr.size()-1)) , g(0,ivecArr.size()-1));
}


然后我们分析一下时间复杂度和空间复杂度。

——————-假设数组长度为N——————————

时间复杂度:O(2ˆN)——因为每个递归的递推式都是:左1=右2

空间复杂度:O(N);

于是想到了动态规划打表,把重复的计算存起来,代码如下:

int getScore(std::vector<int> &ivecArr) {
if (ivecArr.empty()) {
return 0;
}

// 空间复杂度O(Nˆ2)
int length = (int)(ivecArr.size() -1);
int fScore[length+1][length+1];
int gScore[length+1][length+1];

for (int i = 0; i <= length; i++) {
for (int j = 0; j <=length; j++) {
fScore[i][j] = 0;
gScore[i][j] = 0;
}
}

// 时间复杂度O(Nˆ2)
for (int j = 0; j <= length; ++j) {
fScore[j][j] = ivecArr[j];

for (int i = j-1; i >= 0; i--) {
fScore[i][j] = max<int>((gScore[i+1][j] + ivecArr[i]), (gScore[i][j-1] + ivecArr[j]));
gScore[i][j] = min<int>(fScore[i+1][j] , fScore[i][j-1]);
}
}

return max<int>(fScore[0][length],gScore[0][length]);
}

int main(void) {
int iarray[] = {1,100,2};
size_t size = sizeof(iarray) / sizeof(int);
vector<int> ivecArray(iarray,iarray+size);

cout<<"Test case 1 :socre = "<<getScore(ivecArray)<<endl;
}


此方法的时间复杂度O(Nˆ2)—两次遍历;

空间复杂度O(Nˆ2)—打表占的空间;

OKay,完整源码附在下面:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

#ifdef _METHOLD_1_
class Game { public: Game(std::vector<int> &ivecArray) : m_ivecArr(ivecArray) {}; ~Game() {}; int getScore(); int f(int i, int j); int g(int i, int j); private: std::vector<int> &m_ivecArr; }; int Game::f(int i, int j) { if (i == j) { return m_ivecArr[i]; } return max<int>( (m_ivecArr[i] + g(i+1, j)), (m_ivecArr[j] + g(i, j-1)) ); } int Game::g(int i, int j) { if (i == j) { return 0; } return min<int>( f(i+1, j), g(i, j-1) ); } int Game::getScore() { if (ivecArr.empty()) { return 0; } return max<int>(f(0,(ivecArr.size()-1)) , g(0,ivecArr.size()-1)); }

#else

int getScore(std::vector<int> &ivecArr) {
if (ivecArr.empty()) {
return 0;
}

int length = (int)(ivecArr.size() -1);
int fScore[length+1][length+1];
int gScore[length+1][length+1];

for (int i = 0; i <= length; i++) {
for (int j = 0; j <=length; j++) {
fScore[i][j] = 0;
gScore[i][j] = 0;
}
}

for (int j = 0; j <= length; ++j) {
fScore[j][j] = ivecArr[j];

for (int i = j-1; i >= 0; i--) {
fScore[i][j] = max<int>((gScore[i+1][j] + ivecArr[i]), (gScore[i][j-1] + ivecArr[j]));
gScore[i][j] = min<int>(fScore[i+1][j] , fScore[i][j-1]);
}
}

return max<int>(fScore[0][length],gScore[0][length]);
}

#endif
int main(void) {
int iarray[] = {1,100,2};
size_t size = sizeof(iarray) / sizeof(int);
vector<int> ivecArray(iarray,iarray+size);

cout<<"Test case 1 :socre = "<<getScore(ivecArray)<<endl;
}


路漫漫其修远兮,吾将上下…
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 算法