题解 | #24点游戏算法#

24点游戏算法

http://www.nowcoder.com/practice/fbc417f314f745b1978fc751a54ac8cb

我觉得有几个分享的方法不对。
1.没有考虑到用括号的情况。比如:5 9 7 1,这个是能够计算出24的,9-5=4,7-1=6,4*6=24。用他们分享的代码运行是false。
2.对于拿到的第一个数值,有存在0/n的情况,比如:7 8 9 24(虽然24不符合传入要求),他们的代码会存在0/7/8/9=0,再0+24=24,因此返回true,事实上7 8 9 24四个数字无论怎么处理都计算不出24。
所以我自己写了以下代码,还是用的递归,做了一些修改
1.获取第一个数字时,直接将其当成临时结果
2.当已经使用两个数字计算出临时结果传入参数时,对另两个数字进行所有可能值的运算,再与临时结果进行所有可能值比较。
3.对于除法进行判断,确保不会除以0
import java.util.*;
public class Main{
    private static int[] arr;//用于接收传入的4个整数
    private static int[] visited;//用于判断对应序号的整数有没有被使用。
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            arr=new int[4];visited=new int[4];
            for(int i=0;i<4;i++){
                arr[i]=sc.nextInt();
            }
            System.out.println(canGet24(0,0));
        }
    }
    //使用递归,第一个参数表示已使用的数字数,第二个参数表示对已使用的数字进行运算后得到的临时结果
    private static boolean canGet24(int cnt,double tmpres){
        if(cnt==4 && tmpres==24){//如果用了4个了,且结果已经是24了,那就说明24运算成功。
            return true;
        }
        if(cnt==0){//对于还没开始运算的情况,接收的第一个数值直接作为tmpres
            for(int i=0;i<4;i++){
                visited[i]=1;
                if(canGet24(1,arr[i])){
                    return true;
                }
                visited[i]=0;//每一轮循环都要把访问记录恢复
            }
            return false;//所有数字都试过了还没有得到24,说明不可能再得到。
        }
        if(cnt==2){
            //对于已经在两个数值参加运算的情况,要考虑两种可能
            //1.另两个数字参加运算后再和当前结果运算。
            int a=0,b=0;//剩下两个数值取到a,b中
            for(int i=0;i<4;i++){
                if(visited[i]==0){
                    if(a==0){
                        a=arr[i];
                    }else{
                        b=arr[i];
                    }
                }
            }
            for(double n:getAnyRes(a,b)){//对所有可能的ab运算结果进行判断
                for(double m:getAnyRes(tmpres,n)){//对所有可能的tmpres和n的运算结果进行判断
                    if(m==24){
                        return true;
                    }
                }
            }
            //2.当前结果与第三个数值参加运算。
            for(int i=0;i<4;i++){
                if(visited[i]==0){
                    visited[i]=1;
                    if(canGet24(3,tmpres+arr[i])||canGet24(3,tmpres*arr[i])||//加和乘计算
                       canGet24(3,tmpres-arr[i])||canGet24(3,arr[i]-tmpres)){//减法计算
                        return true;
                    }
                    if(tmpres!=0 && canGet24(3,arr[i]/tmpres)
                       ||arr[i]!=0 && canGet24(3,tmpres/arr[i])){//除法计算
                        return true;
                    }
                    visited[i]=0;
                }
            }
            return false;//所有情况都试过了,还是没有24出现,返回false
        }
        if(cnt==1||cnt==3){
            for(int i=0;i<4;i++){
                if(visited[i]==0){
                    visited[i]=1;
                    if(canGet24(cnt+1,tmpres+arr[i])||canGet24(cnt+1,tmpres*arr[i])||//加和乘计算
                       canGet24(cnt+1,tmpres-arr[i])||canGet24(cnt+1,arr[i]-tmpres)){//减法计算
                        return true;
                    }
                    if(tmpres!=0 && canGet24(cnt+1,arr[i]/tmpres)||
                       arr[i]!=0 && canGet24(cnt+1,tmpres/arr[i])){//除法计算
                        return true;
                    }
                    visited[i]=0;
                }
            }
        }//不是1~4的返回false
        return false;
    }
    //以下函数用于返回两个数进行任何运算后可能的值,以列表形式返回。
    private static List<Double> getAnyRes(double a,double b){
        List<Double> res = new ArrayList<Double>();
        res.add(a+b);
        res.add(a*b);
        res.add(a-b);
        res.add(b-a);
        if(a!=0){
            res.add(b/a);
        }
        if(b!=0){
            res.add(a/b);
        }
        return res;
    }
}


全部评论
题目描述本身就有问题,"运算符仅允许出现在两个数字之间" 说明不能考虑括号,因为只要有括号运算符就不可能只出现在两个数字之间,但是后面还有一句 "且需考虑括号运算",所以自相矛盾。答主追求代码的健壮性是正确的,值得大家学习。
6 回复 分享
发布于 2022-08-31 10:50 河南
太强了
3 回复 分享
发布于 2022-07-25 14:46
你这个才对
2 回复 分享
发布于 2022-08-13 13:14
1 5 5 7不通过啊,5*5-1=24。
2 回复 分享
发布于 2022-09-08 17:12 广西
全面
1 回复 分享
发布于 2022-07-25 21:40
需要对两个数运算和0单独考虑!
1 回复 分享
发布于 2022-09-04 12:45 江苏
0 24 1 5 结果为TRUE?
1 回复 分享
发布于 2022-09-29 15:06 山东
厉害,这个才全面
1 回复 分享
发布于 2022-12-07 16:06 美国
7 9 10 9 (9+10)*9/7 结果整数型也是24 这种怎么考虑
1 回复 分享
发布于 2023-03-23 11:31 浙江
这个在面试的时候能写完?不会超时?
1 回复 分享
发布于 2023-04-06 15:29 上海
针对您提到的第二个问题(存在0/n的情况),我暂时没过多分析其他人的代码,不清楚出现的具体原因。 您反馈的第一个问题太给力了,官方的用例也确实没有考虑进去,我个人也确实忽略这种情况了,默认4个数字逐个处理了。基于您的答案,我有两点改进思路,原本想回复里写的,但是回复没有换行,格式太乱,又特意开了博客,单独发了题解,链接:https://www.nowcoder.com/discuss/510426799394795520?sourceSSR=users
点赞 回复 分享
发布于 2023-07-17 12:16 北京
是的,确实存在全部通过测试用例,却不能通过楼主说的例子的问题。
点赞 回复 分享
发布于 2023-12-22 00:09 江苏
其实递归的dfs已经包含了所有情况,你这个写复杂了
点赞 回复 分享
发布于 08-09 15:50 北京
这个感觉不止中等难度
点赞 回复 分享
发布于 11-12 22:36 四川

相关推荐

10-24 11:10
山西大学 Java
若梦难了:哥们,面试挂是很正常的。我大中厂终面挂,加起来快10次了,继续努力吧。
点赞 评论 收藏
分享
45 9 评论
分享
牛客网
牛客企业服务