算法之 数组两端取数游戏

2024-03-19 14:20

本文主要是介绍算法之 数组两端取数游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

  同学A与B玩取数游戏。即有一个2n项的数组,其中每个都是整数且对两位同学都是可见的,两位同学轮流从 两端 取走数字(假设A同学先取)。
胜负评判:所取数之和较大者获胜(可能存在平局)。

分析

  1. 如果题目问A同学的胜负情况,那可以直接回答胜或者平局,因为数组对两位同学都是可见的,都做出最佳决策的情况下肯定是先取者获胜,或者平局。
  2. 如果题目问A同学最后会比B同学多多少分。那么可以用递归求解,我们拿一个具体的例子,{1,3,30,4}  很显然不能用贪心策略,让A同学直接取当前两端的较大值,因为那样的话,很大的30会被B取走,所以可以看出来两次取数之间有关联。我们可以看出来A同学应该取1,然后B同学取4,然后A取30,B取3,最终A同学得分为31,B为7。

    sum( i , j ) 为A同学从数组 a 下标的 i 处到 j 处这个范围下采取最佳决策后的得分与B同学的差值,所以我们最后要求的是sum( 0 , 3 ),表示A同学的最大得分
    那么思考每一步,是取左边的数还是右边的数呢?这取决于 a[左] - sum( 左+1,右)
    a[右] - sum( 左, 右-1 ) 哪个大。这里要注意不是 + 号 而是 - 号,因为A同学取完之后是B同学取。还要注意递归的终止条件。
 public static int fun(int[] a, int i, int j) {if(i +1 == j) return Math.abs(a[i]-a[j]);int temp1 = a[i] - fun(a, i+1, j);int temp2 = a[j] - fun(a, i, j-1);return Math.max(temp1,temp2);}

  鉴于以上递归过程中会大量重复计算值,可能会使递归栈的深度过大导致栈溢出,而且降低了性能,于是考虑使用Dynamic Programming动态规划来解决。
  和一般DP问题一样,有个二维数组来保存记录,DP[n][n] 和以上sum( i , j )的意义一样,n是原数组 a 的大小。
递归表达式:

DP[i][i] =a[i]
DP[i][j] = max(a[i]-DP[i+1][j], a[j]-DP[i][j-1])

写成代码的话就是:

public static int fun2(int[] nums) {int n = nums.length;int[][] dp = new int[n][n];for(int i = 0; i < n; i++)dp[i][i] = nums[i];for(int i = 0; i < n-1; i++)for(int j = i+1; j < n; j++)dp[j-i-1][j] = Math.max(nums[j-i-1] - dp[j-i][j], nums[j] - dp[j-i-1][j-1]);return dp[0][n-1];}

这里要注意的是这个矩阵的填写方向,for循环还有点难写。第一轮运算图

彩蛋

 以上方法在很久之前都见过,也没什么新意。稍加改动就可以求出A,B同学具体取的数字,但是在最近看一本《常用算法与程序设计》的时候,发现了这个题还有更简单粗暴的方式,复杂度是O(n)
 先求出序列中奇数号整数之和S1,再求出偶数号整数之和S2.
那么 | S1 - S2 | 就是A,B同学最终得分的差值了。而且,A同学不是取全体奇数号项,就是取全体偶数项,这个值得动脑筋想想。
还是例子 {1,3,30,4},那么 S1 = 1+30 = 31, S2 = 2+4 = 6
那么要胜的A同学,先取奇数项,即1,然后剩下的能取的3和4都是偶数项,B会取较大的4,然后A继续取数,那么能取的一定是奇数项了。所以证明了取的数是全体奇数项。
由此可见,什么递归,动归,还是逻辑分析动脑筋最重要啊!

这篇关于算法之 数组两端取数游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/826264

相关文章

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

JAVA数组中五种常见排序方法整理汇总

《JAVA数组中五种常见排序方法整理汇总》本文给大家分享五种常用的Java数组排序方法整理,每种方法结合示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录前言:法一:Arrays.sort()法二:冒泡排序法三:选择排序法四:反转排序法五:直接插入排序前言:几种常用的Java数组排序

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代