当前位置: 首页 > news >正文

经典算法题之我能赢吗(二)

解决方案

方法一:记忆化搜索 + 状态压缩

思路和算法

考虑边界情况,当所有数字选完仍无法到达 desiredTotal 时,两人都无法获胜,返回 false 。当所有数字的和大于等于 desiredTotal 时,其中一方能获得胜利,需要通过搜索来判断获胜方。

在游戏中途,假设已经被使用的数字的集合为 usedNumbers ,这些数字的和为 currentTotal 。当某方行动时,如果他能在未选择的数字中选出一个 i ,使得 i+currentTotal ≥ desiredTotal ,则他能获胜。否则,需要继续通过搜索来判断获胜方。在剩下的数字中,如果他能选择一个 i ,使得对方在接下来的局面中无法获胜,则他会获胜。否则,他会失败。

根据这个思想设计搜索函数 dfs ,其中 usedNumbers 可以用一个整数来表示,从低位到高位,第 i 位为 1 则表示数字 i 已经被使用,为 0 则表示数字 i 未被使用。如果当前玩家获胜,则返回 true ,否则返回 false 。为了避免重复计算,需要使用记忆化的操作来降低时间复杂度。

代码

Python3

class Solution: def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool: @cache def dfs(usedNumbers: int, currentTotal: int) -> bool: for i in range(maxChoosableInteger): if (usedNumbers >> i) & 1 == 0: if currentTotal + i + 1 >= desiredTotal or not dfs(usedNumbers | (1 << i), currentTotal + i + 1): return True return False return (1 + maxChoosableInteger) * maxChoosableInteger // 2 >= desiredTot

Java

class Solution { Map<Integer, Boolean> memo = new HashMap<Integer, Boolean>(); public boolean canIWin(int maxChoosableInteger, int desiredTotal) { if ((1 + maxChoosableInteger) * (maxChoosableInteger) / 2 < desiredTotal) { return false; } return dfs(maxChoosableInteger, 0, desiredTotal, 0); } public boolean dfs(int maxChoosableInteger, int usedNumbers, int desiredTotal, int currentTotal) { if (!memo.containsKey(usedNumbers)) { boolean res = false; for (int i = 0; i < maxChoosableInteger; i++) { if (((usedNumbers >> i) & 1) == 0) { if (i + 1 + currentTotal >= desiredTotal) { res = true; break; } if (!dfs(maxChoosableInteger, usedNumbers | (1 << i), desiredTotal, currentTotal + i + 1)) { res = true; break; } } } memo.put(usedNumbers, res); } return memo.get(usedNumbers); } }

C#

public class Solution { Dictionary<int, bool> memo = new Dictionary<int, bool>(); public bool CanIWin(int maxChoosableInteger, int desiredTotal) { if ((1 + maxChoosableInteger) * (maxChoosableInteger) / 2 < desiredTotal) { return false; } return DFS(maxChoosableInteger, 0, desiredTotal, 0); } public bool DFS(int maxChoosableInteger, int usedNumbers, int desiredTotal, int currentTotal) { if (!memo.ContainsKey(usedNumbers)) { bool res = false; for (int i = 0; i < maxChoosableInteger; i++) { if (((usedNumbers >> i) & 1) == 0) { if (i + 1 + currentTotal >= desiredTotal) { res = true; break; } if (!DFS(maxChoosableInteger, usedNumbers | (1 << i), desiredTotal, currentTotal + i + 1)) { res = true; break; } } } memo.Add(usedNumbers, res); } return memo[usedNumbers]; } }

复杂度分析

时间复杂度:O(2*n × n),其中 n = maxChoosableInteger 。记忆化后,函数 dfs 最多调用 O(2*n) 次,每次消耗 O(n) 时间,总时间复杂度为 O(2*n×n) 。

空间复杂度:O(2*n),其中 n = maxChoosableInteger 。搜索的状态有 O(2*n) 种,需要消耗空间记忆化。

http://www.rkmt.cn/news/1417147.html

相关文章:

  • 【零基础部署】Docker 部署 Redis 保姆级教程
  • 小白也能看懂!AI大模型概念清单,收藏这份学习指南轻松入门
  • 从Python列表切片到LLM接口实战:零基础AI编程落地教程
  • taotoken平台api调用稳定性与低延迟实际网络测试感受
  • 从实验室到上车:一份完整的车载毫米波雷达环境与耐久性测试清单
  • 告别杜邦线乱飞!用PCF8574模块和I2C总线,让你的51单片机LCD1602接线清爽起来
  • 2026实测乌鲁木齐四大财税机构:公司注册首选TOP1出炉! - 小柏云
  • GitNexus是Monorepo单体仓库
  • 电磁直线执行器直接驱动的流体控制阀系统【附程序】
  • 模型检验中的对称性破缺技术:应对核电站IC系统验证的组合爆炸
  • 基于Arduino的密码锁系统:从矩阵键盘到伺服电机的完整实现
  • 中国石化仪征化纤有限责任公司特种纤维研究所所长王芳,分享《超高分子量聚乙烯纤维和对位芳纶纤维在工程领域的应用》
  • 2026国产在线余氯监测仪十大品牌深度横评:技术破局与全场景选型指南 - 液体流量液位品牌推荐
  • 投资者信任危机应对全解析,深度解读Gemini IR风控模型与实时舆情响应机制
  • NI-DAQmx模拟设备(SimDev)完全使用指南:没硬件也能玩转数据采集仿真
  • RPGMakerDecrypter完全指南:3步解密RPG Maker加密存档的专业方法
  • 评测全网10款主流降AI率软件:只选真正管用的那一款! - 降AI小能手
  • Python日志系统详解
  • ATtiny85软件PWM驱动RGB氛围灯:中断、防抖与电源设计全解析
  • 从PID控制到反应轮:自制自平衡立方体的完整工程实践
  • 别再纠结了!gtsummary vs compareGroups:R语言画基线表到底该选谁?
  • 大型项目弯头厂家选型参考:五个决策步骤与案例解析 - 速递信息
  • 6G智能超表面优化:从信道可编程到能效与安全性能提升
  • 别再死记ResNet结构了!用PyTorch手搓一个ResNet-18,带你彻底搞懂残差连接
  • 基于Arduino与NRF24L01的无线遥控车DIY全攻略:从电路设计到代码实现
  • 2026年5月电磁流量计生产厂家推荐——污水测量哪款能真正获得市场认可?
  • 从‘像素对错’到‘结构好坏’:一个迭代细化技巧,让你的模型预测自己纠错(Topology Loss实战)
  • SAP PS项目模板搭建保姆级教程:从CJ91到CN13,手把手教你构建企业核心资产
  • 创客教育实战:从电路设计到生活应用的跨学科项目指南
  • 移动端电声乐器音频处理:从DSP算法到硬件接口的完整实现