• 24点游戏解法


    如果说工作是为了更好地玩,那当玩的不开心时,比如24点,还是要用工作技能去处理,下面代码质量不高,纯属娱乐,欢迎指点批评:

    1. public class Main {
    2. private static final double TARGET=24;
    3. public static void main(String[] args) {
    4. Scanner in = new Scanner(System.in);
    5. int[] nums = Arrays.stream(in.nextLine().split(" ")).mapToInt(
    6. Integer::parseInt).toArray();
    7. ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn");
    8. Main m = new Main();
    9. // 15<=>1111
    10. System.out.println(m.dfs(nums, new ArrayList<>(), 15, nashorn));
    11. }
    12. /**
    13. *
    14. * @param nums
    15. * @param formula list 存储表达式子项,之所有选用 List 是为了兼容数字大于9的情况
    16. * @param selected 记录选择标志位
    17. * @param nashorn
    18. * @return
    19. */
    20. public boolean dfs(int[] nums, List formula, int selected, ScriptEngine nashorn) {
    21. if (selected == 0) {
    22. if (formula.size() < 7) {
    23. return false;
    24. }
    25. // todo test
    26. // System.out.println("complete formula: " + formula);
    27. String f = found24(formula, nashorn);
    28. boolean b = !f.isEmpty();
    29. if (b) {
    30. System.out.println(f);
    31. }
    32. return b;
    33. }
    34. boolean ret = false;
    35. for (int i = 0; i < nums.length; ++i) {
    36. int select = nums[i];
    37. int newSelect = setI(i, selected);
    38. if (selected == 15) {//1111
    39. formula.add(String.valueOf(select));
    40. if (!(ret |= dfs(nums, formula, newSelect, nashorn))) {
    41. formula.remove(formula.size() - 1);
    42. continue;
    43. }else{
    44. return true;
    45. }
    46. }
    47. if (!checkI(i, selected)) {
    48. continue;
    49. }
    50. // addition
    51. formula.add("+");
    52. formula.add(String.valueOf(select));
    53. ret |= dfs(nums, formula, newSelect, nashorn);
    54. if (!ret) {
    55. formula.remove(formula.size() - 1);
    56. formula.remove(formula.size() - 1);
    57. } else {
    58. return true;
    59. }
    60. // subtraction
    61. formula.add("-");
    62. formula.add(String.valueOf(select));
    63. ret |= dfs(nums, formula, newSelect, nashorn);
    64. if (!ret) {
    65. formula.remove(formula.size() - 1);
    66. formula.remove(formula.size() - 1);
    67. } else {
    68. return true;
    69. }
    70. // multiplication
    71. formula.add("*");
    72. formula.add(String.valueOf(select));
    73. ret |= dfs(nums, formula, newSelect, nashorn);
    74. if (!ret) {
    75. formula.remove(formula.size() - 1);
    76. formula.remove(formula.size() - 1);
    77. } else {
    78. return true;
    79. }
    80. // division
    81. formula.add("/");
    82. formula.add(String.valueOf(select));
    83. ret |= dfs(nums, formula, newSelect, nashorn);
    84. if (!ret) {
    85. formula.remove(formula.size() - 1);
    86. formula.remove(formula.size() - 1);
    87. } else {
    88. return true;
    89. }
    90. }
    91. return false;
    92. }
    93. /**
    94. * 校验(从右到左)第 i 位是否为1
    95. * @param i
    96. * @param selected
    97. * @return
    98. */
    99. public boolean checkI(int i, int selected) {
    100. return ((selected >> i) & 1) == 1;
    101. }
    102. /**
    103. * 从右到左 第 i 位置为0
    104. * @param i
    105. * @param selected
    106. * @return
    107. */
    108. public int setI(int i, int selected) {
    109. int c = ~(1 << i);
    110. return selected & c;
    111. }
    112. /**
    113. * 枚举各种括号,找出带括号计算后可以得到 24 点的表达式
    114. * @param formula 包含表达式符号的集合
    115. * @param nashorn
    116. * @return 可得 24 点的表达式
    117. */
    118. public String found24(List formula, ScriptEngine nashorn) {
    119. boolean ret = checkValue(calc(formula, nashorn) ,TARGET);
    120. if (ret) {
    121. return buildFormula(formula, null);
    122. }
    123. ArrayList tempFormu = new ArrayList<>();
    124. // (AB)CD A(BC)D AB(CD)
    125. for (int i = 0; i < 3; ++i) {
    126. int end = 3 + i * 2;
    127. int start = end - 3;
    128. // 拼接表达式,一下类似,不重复注释
    129. tempFormu.addAll(formula.subList(0, start));
    130. tempFormu.add("("+String.valueOf(calc(formula.subList(start, end), nashorn)) + ")");
    131. tempFormu.addAll(formula.subList(end, 7));
    132. ret = checkValue(calc(tempFormu,nashorn),TARGET);
    133. if (ret) {
    134. return buildFormula(formula, Arrays.asList(Arrays.asList(start, end)));
    135. }
    136. tempFormu.clear();
    137. }
    138. // (AB)(CD)
    139. tempFormu.add("("+String.valueOf(calc(formula.subList(0, 3), nashorn)) + ")");
    140. tempFormu.addAll(formula.subList(3, 4));
    141. tempFormu.add("("+String.valueOf(calc(formula.subList(4, 7), nashorn))+")");
    142. ret = checkValue(calc(tempFormu,nashorn),TARGET);
    143. tempFormu.clear();
    144. if (ret) {
    145. return buildFormula(formula, Arrays.asList(Arrays.asList(0, 3), Arrays.asList(4, 7)));
    146. }
    147. // (ABC)D A(BCD)
    148. for (int i = 0; i < 2; ++i) {
    149. int end = 5 + i * 2;
    150. int start = end - 5;
    151. tempFormu.addAll(formula.subList(0, start));
    152. tempFormu.add("("+String.valueOf(calc(formula.subList(start, end), nashorn))+")");
    153. tempFormu.addAll(formula.subList(end, 7));
    154. ret = checkValue(calc(tempFormu,nashorn),TARGET);
    155. tempFormu.clear();
    156. if (ret) {
    157. return buildFormula(formula, Arrays.asList(Arrays.asList(start, end)));
    158. }
    159. }
    160. return "";
    161. }
    162. /**
    163. * 校验值 误差 < 1e-6
    164. * @param value
    165. * @param target
    166. * @return
    167. */
    168. public boolean checkValue(double value, double target){
    169. return Math.abs(target-value)<1e-6;
    170. }
    171. /**
    172. * 构建公式的字符串表达式(含有符号)
    173. * @param formulas
    174. * @param idxes 插入括号的下标(两层为了兼容双括号 (AB)(CD))
    175. * @return
    176. */
    177. public String buildFormula(List formulas, List> idxes) {
    178. if (idxes == null) {
    179. return formulas.stream().collect(Collectors.joining());
    180. }
    181. StringBuilder formula = new StringBuilder();
    182. List ids = idxes.get(0);
    183. if (idxes.size() == 1) {
    184. List l1 = formulas.subList(0, ids.get(0));
    185. List l2 = formulas.subList(ids.get(0), ids.get(1));
    186. List l3 = formulas.subList(ids.get(1), 7);
    187. formula.append(l1.stream().collect(Collectors.joining()));
    188. formula.append("(" + l2.stream().collect(Collectors.joining()) + ")");
    189. formula.append(l3.stream().collect(Collectors.joining()));
    190. } else {//双括号只有一种可能
    191. List l1 = formulas.subList(ids.get(0), ids.get(1));
    192. List l2 = formulas.subList(idxes.get(1).get(0), idxes.get(1).get(1));
    193. formula.append("(" + l1.stream().collect(Collectors.joining()) + ")");
    194. formula.append(formulas.get(3));
    195. formula.append("(" + l2.stream().collect(Collectors.joining()) + ")");
    196. }
    197. return formula.toString();
    198. }
    199. public double calc(List formula0, ScriptEngine nashorn) {
    200. try {
    201. String formula = formula0.stream().collect(Collectors.joining());
    202. // todo Test
    203. // System.out.println("calculating : " + formula);
    204. Object result = nashorn.eval(formula);
    205. if (result instanceof Integer) {
    206. return (Integer) result;
    207. }
    208. if (result instanceof Double) {
    209. double d = (Double) result;
    210. return d;
    211. }
    212. return 0;
    213. } catch (ScriptException e) {
    214. return 0;
    215. }
    216. }
    217. }

    一般的算法练习,会让你校验,数字是否满足 24 点规则,参考leetcode679.

    牛客上也有相关题目 HJ67,只不过是用例不全的阉割版,用半成品算法也能通过,参考我这篇

    靠着上述代码,总算通关了 24 点游戏 160+32 个关卡,姑且一乐,需者自取。

  • 相关阅读:
    eggjs controller层调用controller层解决方案
    JS 循环JSON将数据遍历到Table里面
    MySQL 函数 索引 事务 管理
    MySQL常见面试题汇总(建议收藏!!!)
    搜索技术——模拟退火算法
    教你剪辑视频替换封面
    dom的增删改、练习从左到右和从右到左、动态添加和删除行记录
    Element UI +Vue页面生成二维码的方法
    mysql索引常见问题
    计算机网络之物理层
  • 原文地址:https://blog.csdn.net/weixin_41346635/article/details/134467657