数据结构和算法经典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一定把两种情况中小的留给后手选手)
在分析完题目后,我们发现这是一个递归问题,可以暴力递归直接解这个问题,代码如下:
然后我们分析一下时间复杂度和空间复杂度。
——————-假设数组长度为N——————————
时间复杂度:O(2ˆN)——因为每个递归的递推式都是:左1=右2
空间复杂度:O(N);
于是想到了动态规划打表,把重复的计算存起来,代码如下:
此方法的时间复杂度O(Nˆ2)—两次遍历;
空间复杂度O(Nˆ2)—打表占的空间;
OKay,完整源码附在下面:
路漫漫其修远兮,吾将上下…
排成一条线的纸牌博弈问题
给定一个整形数组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;
}
路漫漫其修远兮,吾将上下…
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#数据结构之顺序表(SeqList)实例详解
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- C#数据结构之单链表(LinkList)实例详解
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 数据结构之Treap详解
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解