题目链接
可能做法比较麻烦,就当深搜的练习吧。分两步,第一步枚举所有的可能的运算式,第二步计算每个运算式所有可能的结果,此结果就是任意位置加括号的所有可能结果,与这个力扣题目相似。
注意题目说的是这4个数字任意组合,一开始还固定了顺序,只在数字间枚举算符。
如果提交之后得了5分,原因应该是double数据的比较存在误差,只要计算结果与24的差值小于0.0001就认为表达式可以得到24.
还有要注意的是每个测试样例用的公用数据结构如vis,exps一定要重新初始化或清空,对于mp映射一个子表达式可能的结果,这个对于所有测试样例可以公用,但是也要清空,否则会内存超限制。
import java.util.*;
public class Main{
//拆分成两步来做
//第一步dfs出所有可能的表达式
//第二步对各个表达式分别求所有可能的运算结果(从而体现在不同的位置添加括号改变运算顺序)
public static int [] nums=new int [4];
public static Set<String> exps=new HashSet<String>();
public static boolean[] vis=new boolean[4];
public static void dfs(int cnt,String exp) {
for(int i=0;i<4;i++) {
if(!vis[i]) {
vis[i]=true;
if(cnt==3) {
exps.add(exp+String.valueOf(nums[i]));
vis[i]=false;
return;
}
dfs(cnt+1,exp+String.valueOf(nums[i])+"+");
dfs(cnt+1,exp+String.valueOf(nums[i])+"-");
dfs(cnt+1,exp+String.valueOf(nums[i])+"*");
dfs(cnt+1,exp+String.valueOf(nums[i])+"/");
vis[i]=false;
}
}
}
//记忆化搜索,所有表达式的值都可以从这里面获取,因为相同子表达式的值的结果是固定的
//还是每次都清空吧,否则可能内存超限制
public static Map<String,LinkedList<Double>> mp=new HashMap<String,LinkedList<Double>>();
public static LinkedList<Double> dfs2(String curExp) {
LinkedList<Double> tmp=new LinkedList<Double>();
if(curExp.equals("")) {
return tmp;
}else if(mp.containsKey(curExp)) {
return mp.get(curExp);
}else if(curExp.length()==1 && Character.isDigit(curExp.charAt(0))) {
tmp.addLast(Double.parseDouble(curExp));
mp.put(curExp, tmp);
return tmp;
}
for(int i=0;i<curExp.length();i++) {
if(!Character.isDigit(curExp.charAt(i))) {
LinkedList<Double> a,b;
a=dfs2(curExp.substring(0, i));
b=dfs2(curExp.substring(i+1));
for(int m=0;m<a.size();m++) {
for(int n=0;n<b.size();n++) {
if(curExp.charAt(i)=='+') {
tmp.addLast(a.get(m)+b.get(n));
}else if(curExp.charAt(i)=='-') {
tmp.addLast(a.get(m)-b.get(n));
}else if(curExp.charAt(i)=='*') {
tmp.addLast(a.get(m)*b.get(n));
}else {
tmp.addLast(a.get(m)/b.get(n));
}
}
}
}
}
mp.put(curExp, tmp);
return tmp;
}
public static void main(String[] Args) {
Scanner sc=new Scanner(System.in);
while(sc.hasNextInt()) {
for(int i=0;i<4;i++) {
nums[i]=sc.nextInt();
}
if(nums[0]==0) {
sc.close();
break;//输入都是正整数,所以有一个0就是终止了
}
exps.clear();//需要清空,否则前面的表达式会一直存着
mp.clear();
Arrays.fill(vis, false);
dfs(0,"");//第一个dfs生成所有可能的表达式
boolean flag=false;
// for(int i=0;i<exps.size();i++) {
// System.out.println(exps.get(i));
// }
for(String str:exps) {
dfs2(str);//第二个dfs检查各个表达式所有可能的计算结果
LinkedList<Double> e=mp.get(str);
for(double item:e) {
if(Math.abs(item-24.0)<0.0001) {
flag=true;
break;
}
}
if(flag) {
break;
}
}
if(flag) {
System.out.println("YES");
}else {
System.out.println("NO");
}
}
}
}