题目描述
给出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;
/**
* 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;
}
}