分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击人工智能教程
package live.every.day.ProgrammingDesign.CodingInterviewGuide.RecursionAndDynamicPrograming;
/**
* 排成一条线的纸牌博弈问题
*
* 【题目】
* 给定一个整型数组arr,代表数值不同的纸牌排成一条线。玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿,但是每个玩
* 家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪明。请返回最后获胜者的分数。
*
* 【难度】
* 中等
*
* 【解答】
* 暴力递归的方法中,递归函数一共会有N层,并且是f和s交替出现的。f(i,j)会有s(i+1,j)和s(i,j-1)两个递归分支,s(i,j)也
* 会有f(i+1,j)和f(i,j-1)两个递归分支。所以整体的时间复杂度为O(2^N),额外空间复杂度为O(N)。下面介绍动态规划的方法,
* 如果arr长度为N,生成两个大小为NxN的矩阵f和s,f[i][j]表示函数f(i,j)的返回值,s[i][j]表示函数s(i,j)的返回值。规定
* 一下两个矩阵的计算方向即可。
* 具体过程请参看如下代码中的win2方法。
* 如下的win2方法中,矩阵f和s一共有O(N^2)个位置,每个位置计算的过程都是O(1)的比较过程,所以win2方法的时间复杂度为
* O(N^2),额外空间复杂度为O(N^2)。
*
* @author Created by LiveEveryDay
*/
public class LineUpPoker2 {
public static int win2(int[] arr) {
if (arr == null || arr.length == 0) {
return 0;
}
int[][] f = new int[arr.length][arr.length];
int[][] s = new int[arr.length][arr.length];
for (int j = 0; j < arr.length; j++) {
f[j][j] = arr[j];
for (int i = j - 1; i >= 0; i--) {
f[i][j] = Math.max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);
s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]);
}
}
return Math.max(f[0][arr.length - 1], s[0][arr.length - 1]);
}
public static void main(String[] args) {
int[] arr = {1, 2, 100, 4};
System.out.printf("The score is: %d", win2(arr));
}
}
// ------ Output ------
/*
The score is: 101
*/