基于JS实现计算24点算法代码实例解析


Posted in Javascript onJuly 23, 2020

前言

休息的时候无意间看到群里有人发出了华为的校招题,一开始看题目的时候觉得很简单,于是晚上就试着写了一下,结果写的过程中打脸,不断的整理逻辑不断的重写,但我的性格又是不做出来晚上睡不好的那种,于是在做出来的时候就分享给大家(快凌晨三点了有木有,这校招题难度都达到这级别了?o(???)o)

题目描述

基于JS实现计算24点算法代码实例解析

审题要注意:1+2+3*4是前面三个已经相加为6再乘4,没有括号!!

代码:

<!DOCTYPE html>
<html lang="en">

<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>21点</title>
 <script>

   // 牌和对应的权重
   const pokerBox = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"];//下标+1刚好就是对应的分值
   let calcSym = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];//0,1,2 3,4 5,6,7 8,9分别对应+-*/

   function Calculate(a, b, c) {
    if (c <= 2) return a + b;
    if (c <= 4) return a - b;
    if (c <= 7) return a * b;
    if (c <= 9) return a / b;
    return -1;
   }

   function filter(c) {
    if (c <= 2) return "+";
    if (c <= 4) return "-";
    if (c <= 7) return "*";
    if (c <= 9) return "/";
    return;
   }

   let answer = "NONE";//回复的字符串 默认回复NONE,表示无解
   function Calculate24(a, b, c, d, C1, C2, C3) {
    let sum = Calculate(Calculate(Calculate(a, b, C1), c, C2), d, C3);
    if (sum === 24) answer = `公式为:${a} ${filter(C1)} ${b} ${filter(C2)} ${c} ${filter(C3)} ${d} = ${sum}`;
    return sum;
   }

   // 全排列
   //这里的全排序就是把原先的数组复制一个出来,然后新数组代替原先数组删除该值,temp数组添加该值,当新数组的长度为0,说明转移完成,就把temp数组放入matrix数组中
   function permutation(pokers) {
    let matrix = [];
    const subFunc = (arr, temp) => {
     if (temp.length > 4) temp.length = 4;//为了避免过长
     if (arr.length === 0) matrix.push(temp);
     arr.forEach((elem, i) => {
      subFunc([...arr.slice(0, i), ...arr.slice(i + 1)], [...temp, elem]);
     });
    }
    subFunc(pokers, []);
    return matrix;
   };

   // 计算总数为24
   function Count24(a, b, c, d) {
    calcSym.sort((x, y) => x - y);//升序排序
    if (Calculate24(a, b, c, d, calcSym[0], calcSym[1], calcSym[2]) === 24) return true;//第一次判断如果符合就不需要执行下面的循环了
    let i = 1;//上面判断了一次,因此这里从1开始
    if (calcSym.length <= 10) calcSym = [...new Set(permutation(calcSym).flatMap(item=>item.join()))].map(item=>item.split(","));//二维数组去重,并获取全排的数组(即每一种可能性)
    while (true) {
     if (Calculate24(a, b, c, d, calcSym[i][0], calcSym[i][1], calcSym[i][2]) === 24) return true;
     if (i < calcSym.length - 1) i++;
     else return false;//如果数组遍历完都没
    };
    return false;
   }

   function init() {
    if (calcSym.length === 12) calcSym = permutation(calcSym);//获取全排的数组(即每一种可能性)
   }
   init();//初始化就立即执行

   // 对输入的数字进行一次全排
   function calcNumber(arr) {
    if (Count24(arr[0], arr[1], arr[2], arr[3])) return true;//这一步满足那么下面就不用执行permutation了,因为底层是递归,很消耗性能
    let i = 1;
    if (arr.length <= 4) arr = [...new Set(permutation(arr).flatMap(item=>item.join()))].map(item=>item.split(","));//二维数组去重
    if (arr.length > 1) {
     while (true) {
      if (Count24(arr[i][0], arr[i][1], arr[i][2], arr[i][3])) return true;
      if (i < arr.length - 1) i++;
      else return answer = "NONE";
     }
    };
    return answer = "NONE";
   }

   // 当我输入完光标离开的时候就开始判断并计算
   function pokers(event) {
    let arr = event.value.trim().split(" ");
    if (arr.length > 4) {
     arr.length = 4;
     document.getElementById("poker").value = arr.join(' ');
     alert("您输入的牌数大于4张,这边自动帮您删除");
    }
    if (arr.some(item => !pokerBox.includes(item))) alert("ERROR");
    else {
     let arrNew = arr.map(item => { return pokerBox.indexOf(item) + 1 });//计算权重
     calcNumber(arrNew);//执行计算
    }
   }
   function dialog() { alert(answer) };
 </script>
</head>

<body>
 <!-- 这里设置为失去焦点就开始计算是为了尽量减少用户等待的时间,但注意不要设置为输入就开始计算,否则浏览器会卡到崩溃 -->
 <!-- 由于是遍历数组获取结果,如果用户输入的值不为24,那么系统会查询的很慢,这个时候的优化方案有:
 一、每次用户输入的值和对应的回复保存在一个数组内,下次用户输入时先判断是否在该数组内,不在的时候再执行计算
 二、我们可以先排除一部分不可能的值放入数组,比如用户输入2 2 2 2或A A A A,这种怎么算都不可能为24,如果用户输入的为这一类就直接Pass
 三、先把最耗时的calcSym数组的全排改为用户一进入页面就先异步加载计算 -->
 <input type="text" onblur="pokers(this)" name="21" id="poker">
 <input type="button" onclick="dialog()" value="confirm" />
</body>

</html>

实现的效果:

基于JS实现计算24点算法代码实例解析

基于JS实现计算24点算法代码实例解析

基于JS实现计算24点算法代码实例解析

总结思路:

题目第一眼看到就应该想到递归,之前我是把加减乘除都设为一个方法,想采用面向切面的方式进行计算,但是这种方式逻辑复杂且无法计算复杂一点的公式,因此就改为直接把所有可能出现的结果都拿出来一一比对,只要其中一个为24就终止循环,否则循环结束之后返回NONE;

calcSym=[0,1,2,3,4,5,6,7,8,9];//0,1,23,45,6,78,9分别对应+-*/,这里为三个+,两个-,三个*,两个除,大家可以推理得出,6+6+6+6,1*2*3*4,2*13-1-1,13*13/13+11等等,除号和减号最多只可能有两个,而加号和乘号最多可以为三个;

至于全排列方法permutation,是借鉴了STL的next_permutation函数(C++),之所以二维数组去重也是封装的方法可能出现多个数组重复的情况,要知道每多一个数组,底层是用递归查询一遍,浏览器会非常卡;

最后就是我在代码中提到的优化方法,有兴趣的小伙伴可以去试一下,代码还有优化的空间。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
通过JS动态创建一个html DOM元素并显示
Oct 15 Javascript
JavaScript中的Repaint和Reflow用法详解
Jul 27 Javascript
Three.js学习之文字形状及自定义形状
Aug 01 Javascript
JS实现间歇滚动的运动效果实例
Dec 22 Javascript
jquery实现(textarea)placeholder自动换行
Dec 22 Javascript
如何获取元素的最终background-color
Feb 06 Javascript
Bootstrap Table快速完美搭建后台管理系统
Sep 20 Javascript
Vue框架里使用Swiper的方法示例
Sep 20 Javascript
使用koa2创建web项目的方法步骤
Mar 12 Javascript
微信小程序实现的一键连接wifi功能示例
Apr 24 Javascript
搭建一个Koa后端项目脚手架的方法步骤
May 30 Javascript
JS实现继承的几种常用方式示例
Jun 22 Javascript
javascript递归函数定义和用法示例分析
Jul 22 #Javascript
简单了解vue 插值表达式Mustache
Jul 22 #Javascript
详解node.js 事件循环
Jul 22 #Javascript
jQuery+ThinkPHP实现图片上传
Jul 23 #jQuery
详解vue中v-on事件监听指令的基本用法
Jul 22 #Javascript
使用vue实现通过变量动态拼接url
Jul 22 #Javascript
浅谈JavaScript窗体Window.ShowModalDialog使用
Jul 22 #Javascript
You might like
mysql建立外键
2006/11/25 PHP
用PHP查询搜索引擎排名位置的代码
2010/01/05 PHP
PHP cURL初始化和执行方法入门级代码
2015/05/28 PHP
一份老外写的XMLHttpRequest代码多浏览器支持兼容性
2007/01/11 Javascript
javascript高亮效果的二种实现方法
2008/09/14 Javascript
js实现图片放大缩小功能后进行复杂排序的方法
2012/11/08 Javascript
动态读取JSON解析键值对的方法
2014/06/03 Javascript
EasyUi datagrid 实现表格分页
2015/02/10 Javascript
js实现楼层效果的简单实例
2016/07/15 Javascript
9个让JavaScript调试更简单的Console命令
2016/11/14 Javascript
vue 里面使用axios 和封装的示例代码
2017/09/01 Javascript
Java设计中的Builder模式的介绍
2018/03/22 Javascript
JS实现键值对遍历json数组功能示例
2018/05/30 Javascript
JS返回页面时自动回滚到历史浏览位置
2018/09/26 Javascript
小程序从手动埋点到自动埋点的实现方法
2019/01/24 Javascript
js获取对象,数组所有属性键值(key)和对应值(value)的方法示例
2019/06/19 Javascript
Vue el-autocomplete远程搜索下拉框并实现自动填充功能(推荐)
2019/10/25 Javascript
webpack DllPlugin xxx is not defined解决办法
2019/12/13 Javascript
JavaScript Window窗口对象属性和使用方法
2020/01/19 Javascript
electron踩坑之remote of undefined的解决
2020/10/06 Javascript
[01:10]DOTA2次级职业联赛 - U5战队宣传片
2014/12/01 DOTA
python使用fcntl模块实现程序加锁功能示例
2017/06/23 Python
pygame实现贪吃蛇游戏(下)
2019/10/29 Python
python为Django项目上的每个应用程序创建不同的自定义404页面(最佳答案)
2020/03/09 Python
详解CSS3阴影 box-shadow的使用和技巧总结
2016/12/03 HTML / CSS
canvas绘制文本内容自动换行的实现代码
2019/01/14 HTML / CSS
移动端html5 meta标签的神奇功效
2016/01/06 HTML / CSS
Ray-Ban雷朋美国官网:全球领先的太阳眼镜品牌
2016/07/20 全球购物
中国专业的综合网上购物商城:京东
2016/08/02 全球购物
Zooplus罗马尼亚:宠物食品和配件
2019/11/02 全球购物
英国家具、照明、家居用品网上商店:Wayfair.co.uk
2020/02/13 全球购物
元旦活动感言
2014/03/08 职场文书
综合实践活动总结
2014/05/05 职场文书
医院护士党的群众路线教育实践活动对照检查材料思想汇报
2014/10/04 职场文书
工作失职检讨书
2015/01/26 职场文书
2016年党员干部廉政承诺书
2016/03/24 职场文书