【华为OJ】【097-24点游戏算法】

【华为OJ】【算法总篇章】

【华为OJ】【097-24点游戏算法】

【工程下载】

题目描述

给出4个1-10的数字,通过加减乘除,得到数字为24就算胜利
输入:
4个1-10的数字。[数字允许重复,测试用例保证无异常数字]
输出:
true or false

输入描述

输入4个int整数

输出描述

返回能否得到24点,能输出true,不能输出false

输入例子

7 2 1 10

输出例子

true

算法实现

import java.util.LinkedList;
import java.util.Scanner;

/** * Author: 王俊超 * Date: 2016-05-04 12:09 * CSDN: http://blog.csdn.net/derrantcm * Github: https://github.com/Wang-Jun-Chao * Declaration: All Rights Reserved !!! */
public class Main {


    public static void main(String[] args) {
// Scanner scanner = new Scanner(System.in);
        Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data.txt"));
        while (scanner.hasNext()) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            int c = scanner.nextInt();
            int d = scanner.nextInt();

            System.out.println(game24Points(a, b, c, d));

        }
        scanner.close();
    }

    // a, b, c, d都在[1, 10]内

    /** * 4个[1, 10]的能否通过加减乘除,得到数字为24 * * @param a 第一个数字 * @param b 第二个数字 * @param c 第三个数字 * @param d 第四个数字 * @return true,可以组成24,false不可以组成24 */
    private static boolean game24Points(int a, int b, int c, int d) {
        int[] arr = {a, b, c, d, '+', '-', '*', '/'};
        boolean[] used = new boolean[arr.length];
        LinkedList<Integer> list = new LinkedList<Integer>();

        boolean[] rst = {false};

        // 构造组合的逆波兰表达式
        for (int i = 0; i < 4; i++) {
            used[i] = true;
            list.add(arr[i]);
            to24(arr, used, 1, 0, list, rst);

            if (rst[0]) {
                return true;
            }

            // 现场还原
            list.removeLast();
            used[i] = false;
        }


        return false;
    }

    /** * 4个[1, 10]的能否通过加减乘除,得到数字为24 * * @param arr 能够使用的操作数、操作符的数组 * @param used 已经使用的操作数、操作符标记数组 * @param numCnt 操作数的个数 * @param optCnt 操作符的个数 * @param list 求得的逆波兰式 * @param rst 保存中间结果,有满足24的就停止计算 */
    private static void to24(int[] arr, boolean[] used, int numCnt, int optCnt,
                             LinkedList<Integer> list, boolean[] rst) {


        // 如果已经找到答案就不进行操作了
        if (rst[0]) {
            return;
        }
        // 已经完成了逆波兰式的构造
        if (numCnt > optCnt && numCnt + optCnt == 7) {
            calInversePoland(list, rst);
        }
        // 还要构造逆波兰式
        else if (numCnt > optCnt) {

            for (int i = 0; i < arr.length; i++) {
                // 如果arr[i]还没有被使用过,或者arr[i]是运算符
                if (!used[i] || arr[i] < 0 || arr[i] > 10) {
                    // 如果是数字
                    if (arr[i] >= 0 && arr[i] <= 10) {
                        list.add(arr[i]);
                        numCnt++;
                        used[i] = true;

                        to24(arr, used, numCnt, optCnt, list, rst);

                        // 找到了一个答案就返回
                        if (rst[0]) {
                            return;
                        }

                        list.removeLast();
                        numCnt--;
                        used[i] = false;

                    }
                    // 如果是操作符,则放入arr[i]之前,操作数必须比操作符多两个
                    else if (numCnt + 1 > optCnt) {
                        list.add(arr[i]);
                        optCnt++;
                        used[i] = true;

                        to24(arr, used, numCnt, optCnt, list, rst);

                        // 找到了一个答案就返回
                        if (rst[0]) {
                            return;
                        }
                        list.removeLast();
                        optCnt--;
                        used[i] = false;
                    }
                }
            }

        }


    }

    /** * 计算逆波兰式的值 * * @param list 逆波兰式 * @param rst 用于保存计算结果 */
    private static void calInversePoland(LinkedList<Integer> list, boolean[] rst) {
        LinkedList<Double> stack = new LinkedList<>();

        for (int v : list) {

            // 如果是数字
            if (v >= 0 && v <= 10) {
                stack.add((double)v);
            } else {
                double a = stack.removeLast();
                double b = stack.removeLast();
                double c = 0;
                switch ((char) v) {
                    case '+':
                        c = a + b;
                        break;
                    case '-':
                        c = a - b;
                        break;
                    case '*':
                        c = a * b;
                        break;
                    case '/':
                        // 除数不能为0
                        if (a == 0) {
                            return;
                        }
                        c = b / a;
                        break;
                }

                stack.add(c);
            }
        }



        rst[0] = stack.getFirst() == 24.0;
    }

}

你可能感兴趣的:(java,算法,华为)