JS实现求解24点(穷举法)

分享一段用JS写的,求解24点的算法。思路是简单粗暴的穷举法。
该算法很灵活,不单单只能求解4个数。也可求解其它数量的数。而且目标也不单单是24,你也可以设置为求解其它值。先看下用法:

var numArr = [1,2,3,4];
if(true == permute(numArr)){
	console.log(operationProcess);
}
  1. 你先自己定义一个数组,存放你要计算的数据。不一定是4个元素,也可以是其它的长度。内容也不限于1-9,也可以是更大的数字。例如

numArr = [7,5,9,25,75,66,84]

  1. 然后调用permute。如果它返回true,那你就可以在变量operationProcess中拿到计算步骤了。

无解的情况下,整个穷举过程大概0.1秒左右,有解时,则10ms就能解出答案。

在这里插入图片描述
在这里插入图片描述
界面是我自己写的,下面只给出计算部分的代码。

完整代码

	const ops = ['+', '-', '*', '/'];
	
	//用以存放计算过程的数组,每一个元素都是文本
	var operationProcess = [];
	
	//返回num op num2的结构,op是四则运算中的某一种运算符
	function solve24_try_calculate_do(num1, op, num2){
		switch(op){
			case '+':
			return num1 + num2;
			case '-':
			return num1 - num2;
			case '*':
			return num1 * num2;
			case '/':
			if(num2 == 0){return null;}
			else{return num1 / num2;}
		}
		return null;
	}

	
	//递归,它可以将remining中的数排列到current中,会遍历出所可能的组合
	function backtrack(current, remaining) {
	    if (remaining.length === 0) {//当remining为空时,意味着current拿到某一种组合
			//我们把这个组合复制出来,并将它的头两个元素进行四则运算,得到一个新的数组。例如[a, b, c, d...]得到[a+b, c, d...]
			var copyCurrent = JSON.parse(JSON.stringify(current));//深度复制,制造副本
			var a = copyCurrent[0];
			var b = copyCurrent[1];
			copyCurrent.splice(0, 2);
			
			//尝试加减乘除四种运算,得到四种新的数组,并做为新的递归参数
			for (var i = 0; i < ops.length; i++) {
				var ret = solve24_try_calculate_do(a, ops[i], b);	//计算头两个元素
				if(ret == null){continue;}							//计算失败,例如被除数为0的情况,执行跳过
				operationProcess.push(a + ops[i] + b + "=" + ret);	//把计算步骤压入栈
				copyCurrent.unshift(ret)							//计算结果组成新的数组
				if(true == permute(copyCurrent)){return true};		//递归,计算结果。如果返回true表示计算24点成功。此处进行了返回。某你想得到更多的解,此处可以不返回。并将当前栈保存起来。
				copyCurrent.splice(0, 1);							//去掉新元素,准备尝试进行其它运算符
				operationProcess.splice(operationProcess.length-1, 1);//步骤出栈
			}
			
	    }
	    
		//这里是backtrack的递归核心,原理是把remaining中某一个元素拿到current中,将进入下一层递归。
	    for (let i = 0; i < remaining.length; i++) {
	        current.push(remaining[i]);
	        const newRemaining = remaining.slice(0, i).concat(remaining.slice(i + 1));
	        if(backtrack(current, newRemaining) == true){return true};
	        current.pop();
	    }
	}
	
	
	function permute(nums) {
		//如果nums只有一个值,则表示计算已经完成
		if(nums.length == 1){
			if(nums[0] == 24){//当值为24,意味着前面的计算有了成功的结果。返回true。此时可以在operationProcess中得到计算过程
				// console.log("success");
				// for (var i = 0; i < operationProcess.length; i++) {
				// 	console.log(operationProcess[i]);
				// }
				return true;
			}
			else{
				//若值不为24,则表示计算失败了,当前组合得不到24
				return false;
			}
		}
		
		//如果nums不是只有一个值,则把nums做为参数,进行遍历,以求它的所有排列组合进行四则运算
	    if(true == backtrack([], nums)){
			return true;
		}
	    return false;
	}

如果你希望求解其它目标值,可以修改这一句代码:

if(nums[0] == 24)

如果你希望得到更多求解结果,你可以在这里不要返回true,并把当前operationProcess给深度复制,保存到其它地方。

if(true == permute(copyCurrent)){return true};
修改为
if(true == permute(copyCurrent)){
	//自己实现一个方法来保存当前结果
	save(JSON.parse(JSON.stringify(operationProcess)))
};

但递归求解的缺点是很多结果是重复的。例如10+14跟14+10,对于递归来讲,是两种不同的结果。但在人看来,就是一样的。

注意事项

每次调用前,你需要先清空operationProcess。否则它里面会保留上一次的步骤

operationProcess = [];
permute(numArr);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值