当前位置:网站首页>暴力递归到动态规划 02 (绝顶聪明的人的纸牌游戏)
暴力递归到动态规划 02 (绝顶聪明的人的纸牌游戏)
2022-07-29 13:47:00 【涛涛英语学不进去】
1.题目
什么是绝顶聪明,比如有指派 50 100 20 10 ,绝顶聪明的人第一次手会选择10,则后手不管选哪个,这个先手都能取得100,最后取得最大总和,成为赢家
2. 暴力递归
递归终止条件,如果只剩最后一张牌,则先手拿走,如果是后手,则为0,因为先手给拿走了
每次会从 最左边 和 后手的最大值 之和 与 最右边 和 后手最大值 之和 取较大值
先手取完后,后手变为先手,而后手当前值为上一个先手给留的较小值。
public int cardsInLine(int[] arr) {
//如果无值
if (arr == null || arr.length == 0) {
return -1;
}
//返回赢家的分数
return Math.max(first(arr, 0, arr.length - 1), second(arr, 0, arr.length - 1));
}
//先手
private int first(int[] arr, int left, int right) {
//如果只剩最后一张牌了,则先手拿走,后手无
if (left == right) {
return arr[left];
}
//先手从牌中取最大值 50 100 20 10
//如果先手第一次拿50,第二次就只能拿10 60
int leftCard = arr[left] + second(arr, left + 1, right);
//如果先手第一次拿10,第二次就只能拿100 110
int rightCard = arr[right] + second(arr, left, right - 1);
//返回先手所能选择的最大值
return Math.max(leftCard, rightCard);
}
//后手
public int second(int[] arr, int left, int right) {
//后手无牌
if (left == right) {
return 0;
}
//后手不用加 arr[left] arr[right] 他没得选择
//此时后手变为了先手
int leftCard = first(arr, left + 1, right);
int rightCard = first(arr, left, right - 1);
//这个返回值,是给上一个先手用的,因为当前后手会给你留一个小的
return Math.min(leftCard, rightCard);
}
3. 动态规划
public int cardsInLine2(int[] arr) {
//如果无值
if (arr == null || arr.length == 0) {
return -1;
}
int n = arr.length;
//先手数组
int[][] firstArr = new int[n][n];
//后手数组
int[][] secondArr = new int[n][n];
//没填值时初始化为-1
for (int i = 0; i <n ; i++) {
for (int j = 0; j <n ; j++) {
firstArr[i][j] = -1;
secondArr[i][j] = -1;
}
}
//返回赢家的分数
return Math.max(first2(arr, 0, arr.length - 1, firstArr, secondArr), second2(arr, 0, arr.length - 1, firstArr, secondArr));
}
private int first2(int[] arr, int left, int right, int[][] firstArr, int[][] secondArr) {
//如果这个位置的元素已经计算出来,直接返回当前元素
if (firstArr[left][right] != -1) {
return firstArr[left][right];
}
//如果只有一个牌
if (left == right) {
firstArr[left][right] = arr[left];
return firstArr[left][right];
}
//否则计算
int getLeft = arr[left] + second2(arr, left + 1, right, firstArr, secondArr);
int getRight = arr[right] + second2(arr, left, right - 1, firstArr, secondArr);
firstArr[left][right] = Math.max(getLeft, getRight);
return firstArr[left][right];
}
private int second2(int[] arr, int left, int right, int[][] firstArr, int[][] secondArr) {
if (secondArr[left][right] != -1) {
return secondArr[left][right];
}
//如果只有一个牌
if (left == right) {
secondArr[left][right] = 0;
return secondArr[left][right];
}
//后手此时作为先手,取值
int getLeft =first2(arr, left+1, right, firstArr, secondArr);
int getRight = first2(arr, left, right-1, firstArr, secondArr);
secondArr[left][right] = Math.min(getLeft, getRight);
return secondArr[left][right];
}
4. 动态规划优化
public int cardsInLine3(int[] arr) {
//如果无值
if (arr == null || arr.length == 0) {
return -1;
}
int n = arr.length;
//先手数组
int[][] firstArr = new int[n][n];
//后手数组
int[][] secondArr = new int[n][n];
//初始化先手数组对角线元素为最后一张牌时的选择,后手数组为0
for (int i = 0; i <n ; i++) {
firstArr[i][i] = arr[i];
}
// L为横,R为纵
//两个二维数组只用右上角,因为 L<=R横成立
// firstArr[0][0]已经赋值过了
for (int i = 1; i < n; i++) {
int left = 0;
int right = i;
while (right < n) {
firstArr[left][right] = Math.max(arr[left] + secondArr[left + 1][right], arr[right] + secondArr[left][right - 1]);
secondArr[left][right] = Math.min(firstArr[left + 1][right], firstArr[left][right - 1]);
left++;
right++;
}
}
//返回赢家的分数
return Math.max(firstArr[0][n-1],secondArr[0][n-1]);
}
public static void main(String[] args) {
System.out.println(new CardsInLine().cardsInLine(new int[]{
5, 7, 4, 5, 8, 1, 6, 0, 3, 4, 6, 1, 7}));
System.out.println(new CardsInLine().cardsInLine2(new int[]{
5, 7, 4, 5, 8, 1, 6, 0, 3, 4, 6, 1, 7}));
System.out.println(new CardsInLine().cardsInLine3(new int[]{
5, 7, 4, 5, 8, 1, 6, 0, 3, 4, 6, 1, 7}));
}
边栏推荐
- TCP流量控制和拥塞控制
- How to set the explosion rate of legendary humanoid?Humanoid increase tutorial
- 在金融服务行业数字化转型中,低代码值得被关注
- 唯物辩证法-矛盾论(普遍性+特殊性+斗争性+同一性)
- 【堡垒机小知识】硬件堡垒机是什么意思?其与云堡垒机有什么区别?
- 力扣 206.反转链表--递归解决
- 程序员是职业病高发群体,别天真的以为只有秃头那么简单,才不是呢。
- IJCAI 2022 outstanding papers published, China won two draft in 298 the first author
- 一文搞懂JS的原型链
- 新来技术总监:谁在用 isXxx 形式定义布尔类型,明天不用来了!
猜你喜欢
gdb调试常用概念整理
Alibaba CTO Cheng Li: open source is the source of basic software!
深开鸿:万物智联的大江上,升起一轮开源鸿蒙月
iMedicalLIS监听程序(1)
即时通讯移动端开发之网络连接优化
抓住这几个关键点,做薪酬数据分析并不难
【FreeSwitch开发实践】自定义模块创建与使用
力扣 206.反转链表--递归解决
The 10,000-character long article reveals the secrets of Huawei's data governance system!
Gee engine modification UI interface graphic tutorial
随机推荐
trivy如何从非关系型数据库查询数据
How much do you know about futures contracts
1191. 家谱树
Hash table implementation code
AI全流程开发难题破解之钥
The key to cracking AI full-process development problems
已解决SyntaxError: invalid character in identifier
How to Improve Embedded Programming with MISRA
熊市下PLATO如何通过Elephant Swap,获得溢价收益?
MySQL8.0学习记录21 - 视图
plsql连接oracle使用完毕之后关闭问题
Understand the yolov7 network structure
线程池面试汇总
IJCAI 2022 outstanding papers published, China won two draft in 298 the first author
gdb调试常用概念整理
你真的会用Console.log吗?
AI全流程开发难题破解之钥
Gee engine modification UI interface graphic tutorial
1184. 欧拉回路
如何使用MISRA改进嵌入式编程