1.迭代通项
2.四则运算
[一]
x1, x2, x3, x4,四个数属于[1, 10]
f(x1, x2, x3, x4),f表示四个数之间加减乘除且每个数字仅使用一次计算得到的结果
如果结果列表存在24返回true,否则false。
[二]
f: 多种算式
条件:运算符号为+ - * /,考虑括号
每个数字在算式出现一次
目标:f的所有结果列表,即需得到f通项结果,即需要得到f通项算式,即需要得到f算式列表
通项算式:
组成:数字、数子间3个符号、小括号对
[三]
数字: x 符号; s1一级符号, s2二级符号
A括号只有小括号(ok)
(x s2 x) s1 x s1 x
s2 s1 s1
[x s2 (x s2 x)] s1 x
等价于(x s2 x s2 x) s1 x
s2 s2 s1
[x s1 (x s2 x)] s1 x
等价于x s1 (x s2 x) s1 x
s1 s2 s1
s1 s1 s2
综上:无需中括号,只需小括号
B小括号数:最多两对
零对:x s1 x s1 x s1 x
一对:(x s1 x) s1 x s1 x
x s1 (x s1 x) s1 x
x s1 x s1 (x s1 x)
(x s1 x s1 x) s1 x
x s1 (x s1 x s1 x)
两对:(x s1 x) s1 (x s1 x)
[五]
迭代通式:
迭代法遍历数字和符号,获取无括号通项算式,基于无括号通项算式获得有括号通项算式。
迭代法本质:(((xsx)sx)sx)
迭代衍码:
f(x, list)=x
f(x s x s x, list) 值确定
f(x s x s x s x, list) = f( f(x s x s x) s x, list)
4! 已用数子坐标list,用于过滤数和确定返回最终结果。
统计如下:
str=""
str=x1+s1+x2+s2+x3+s3+x4
算式个数:72464=10752
括号对数(对数及位置):7个
符号组合数:444=64个
数子组合数:432*1=24个
通项结果:
g(str):四则运算
[六]
迭代通项代码
/**
* 24点游戏算法
* 1.通项算式
* 2.四则运算
* @author zhuyq
* @date 2020-12-08
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.tellhow.czp.netorder.app.nowcoder.huawei.Arithmetic;
public class TwentyFourPointGameArithmetic {
private static String points = "24";
public static ArrayList<String> arithmeticStrWithoutBracketList = new ArrayList<>();
public static void main(String[] args){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = null;
try {
while((str = br.readLine())!= null){
String[] strArr = str.split(" ");
ArrayList<Integer> numberList = new ArrayList<>();
for(int i=0; i<strArr.length; i++){
Integer val = Integer.valueOf(strArr[i]);
numberList.add(val);
}
ArrayList<String> arithmeticStrList = getArithmeticStrList1(numberList);
ArrayList<String> arithmeticResultList = getArithmeticResultList(arithmeticStrList);
boolean result = isTwentyFourPoint(arithmeticResultList);
System.out.println(result);
ArrayList<String> twentyFourPointarithmeticResultList = getTwentyFourPointArithmeticResultList(arithmeticStrList);
for(String s: twentyFourPointarithmeticResultList){
System.out.println(s);
}
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 判断是否24点
* @author zhuyq
* @date 2020-12-08
*/
public static boolean isTwentyFourPoint(ArrayList<String> arithmeticResultList){
boolean isTwentyFourPoint = false;
for(int i=0; i<arithmeticResultList.size(); i++){
String result = arithmeticResultList.get(i);
if(result.equals(points)){
isTwentyFourPoint = true;
break;
}
}
return isTwentyFourPoint;
}
/**
* 获取24点算式列表
* @author zhuyq
* @date 2020-12-08
*/
public static ArrayList<String> getTwentyFourPointArithmeticResultList(ArrayList<String> arithmeticStrList){
ArrayList<String> twentyFourPointarithmeticResultList = new ArrayList<>();
for(int i=0; i<arithmeticStrList.size(); i++){
String arithmeticStr = arithmeticStrList.get(i);
String result = Arithmetic.arithmeticCaculate(arithmeticStr);
if(result.equals(points)){
twentyFourPointarithmeticResultList.add(arithmeticStr);
}
}
return twentyFourPointarithmeticResultList;
}
/**
* 算式结果列表
* @author zhuyq
* @date 2020-12-08
*/
public static ArrayList<String> getArithmeticResultList(ArrayList<String> arithmeticStrList){
ArrayList<String> arithmeticResultList = new ArrayList<>();
for(int i=0; i<arithmeticStrList.size(); i++){
String arithmeticStr = arithmeticStrList.get(i);
String result = Arithmetic.arithmeticCaculate(arithmeticStr);
arithmeticResultList.add(result);
}
return arithmeticResultList;
}
/**
* 迭代替换多层for
*
* f(x, list)=x
* f(x s x s x, list) 值确定
* f(x s x s x s x, list) = f( f(x s x s x) s x, list)
*
* list:已用数子坐标列表,用于过滤数和确定返回最终结果
*
* 细节点:迭代法参数有list,list必须clone
*
* @author zhuyq
* @date 2020-12-09
*/
public static ArrayList<String> getArithmeticStr(ArrayList<Integer> numberList, ArrayList<String> symbolList, String x, ArrayList<Integer> list){
if(list.size()==4){
arithmeticStrWithoutBracketList.add(x);
}
else{
for(int i=0; i<numberList.size(); i++){
boolean isExist = false;
for(int j=0; j<list.size(); j++){
if(list.get(j).equals(i)){
isExist = true;
}
}
if(!isExist){
ArrayList<Integer> list1 = (ArrayList<Integer>) list.clone();
list1.add(i);
for(int j=0; j<symbolList.size(); j++){
getArithmeticStr(numberList, symbolList, x+symbolList.get(j)+numberList.get(i), list1);
}
}
}
}
return arithmeticStrWithoutBracketList;
}
/**
* 算式列表
* @author zhuyq
* @date 2020-12-09
*/
public static ArrayList<String> getArithmeticStrList1(ArrayList<Integer> numberList){
ArrayList<String> arithmeticStrList = new ArrayList<>();
ArrayList<String> symbolList = new ArrayList<>();
symbolList.add("+");
symbolList.add("-");
symbolList.add("*");
symbolList.add("/");
for(int i=0; i<numberList.size(); i++){
ArrayList<Integer> list = new ArrayList<>();
list.add(i);
String x = String.valueOf(numberList.get(i));
/**
* 零对:x s1 x s1 x s1 x
*/
getArithmeticStr(numberList, symbolList, x, list);
}
/**
* 通项算式(有括号)
*/
for(int i=0; i<arithmeticStrWithoutBracketList.size(); i++){
String arithmeticStrWithoutBracket = arithmeticStrWithoutBracketList.get(i);
ArrayList<String> bracketArithmeticStrList = getBracketArithmeticStrListForSpecifiedArithmeticStr(arithmeticStrWithoutBracket);
arithmeticStrList.add(arithmeticStrWithoutBracket);
for(int j=0; j<bracketArithmeticStrList.size(); j++){
arithmeticStrList.add(bracketArithmeticStrList.get(j));
}
}
return arithmeticStrList;
}
/**
* 通项算式(有括号)
* 一对:(x s1 x) s1 x s1 x
* x s1 (x s1 x) s1 x
* x s1 x s1 (x s1 x)
* (x s1 x s1 x) s1 x
* x s1 (x s1 x s1 x)
* 两对:(x s1 x) s1 (x s1 x)
*/
public static ArrayList<String> getBracketArithmeticStrListForSpecifiedArithmeticStr(String arithmeticStr){
ArrayList<String> bracketArithmeticStrList = new ArrayList<>();
ArrayList<String> bracketList = new ArrayList<>();
bracketList.add("(");
bracketList.add(")");
String regex = "[\\+\\-\\*/]";
String[] numArr = arithmeticStr.split(regex);
String[] symbolArr = new String[3];
Matcher slashMatcher = Pattern.compile(regex).matcher(arithmeticStr);
int idx = -1;
while(slashMatcher.find()) {
idx++;
symbolArr[idx] = slashMatcher.group();
}
String x1 = numArr[0];
String x2 = numArr[1];
String x3 = numArr[2];
String x4 = numArr[3];
String s1 = symbolArr[0];
String s2 = symbolArr[1];
String s3 = symbolArr[2];
StringBuilder sb1 = new StringBuilder();
sb1.append(bracketList.get(0)).append(x1).append(s1).append(x2).append(bracketList.get(1)).append(s2).append(x3).append(s3).append(x4);
StringBuilder sb2 = new StringBuilder();
sb2.append(x1).append(s1).append(bracketList.get(0)).append(x2).append(s2).append(x3).append(bracketList.get(1)).append(s3).append(x4);
StringBuilder sb3 = new StringBuilder();
sb3.append(x1).append(s1).append(x2).append(s2).append(bracketList.get(0)).append(x3).append(s3).append(x4).append(bracketList.get(1));
StringBuilder sb4 = new StringBuilder();
sb4.append(bracketList.get(0)).append(x1).append(s1).append(x2).append(s2).append(x3).append(bracketList.get(1)).append(s3).append(x4);
StringBuilder sb5 = new StringBuilder();
sb5.append(x1).append(s1).append(bracketList.get(0)).append(x2).append(s2).append(x3).append(s3).append(x4).append(bracketList.get(1));
StringBuilder sb6 = new StringBuilder();
sb6.append(bracketList.get(0)).append(x1).append(s1).append(x2).append(bracketList.get(1)).append(s2).append(bracketList.get(0)).append(x3).append(s3).append(x4).append(bracketList.get(1));
bracketArithmeticStrList.add(sb1.toString());
bracketArithmeticStrList.add(sb2.toString());
bracketArithmeticStrList.add(sb3.toString());
bracketArithmeticStrList.add(sb4.toString());
bracketArithmeticStrList.add(sb5.toString());
bracketArithmeticStrList.add(sb6.toString());
return bracketArithmeticStrList;
}
/**
* 基于list去掉指定项返回新(不同指针)的list
* @author zhuyq
* @date 2020-12-08
*/
public static ArrayList<Integer> getNewListByRemove(ArrayList<Integer> numberList, int i){
ArrayList<Integer> numberList1 = new ArrayList<>();
for(int k=0; k<numberList.size(); k++){
Integer xk = numberList.get(k);
if(k!=i){
numberList1.add(xk);
}
}
return numberList1;
}
}
四则算法代码如下:
package com.tellhow.czp.netorder.app.nowcoder.huawei;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.tellhow.czp.netorder.app.nowcoder.huawei.entity.UnitExpression;
import com.tellhow.czp.netorder.app.nowcoder.huawei.util.StrUtil;
/**
* 四则运算
* @author zhuyq
* @date 2020-11-11
*/
public class Arithmetic {
public static void main(String[] args){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String strExpression = null;
try {
while((strExpression = br.readLine())!= null){
String result = arithmeticCaculate(strExpression);
System.out.println(result);
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 四则运算
* @author zhuyq
* @date 2020-11-11
*/
public static String arithmeticCaculate(String strExpression){
/*************************括号运算开始*****************************/
//小括号运算
strExpression = bracketCaculate(strExpression, "()");
//中括号运算
strExpression = bracketCaculate(strExpression, "[]");
//大括号运算
strExpression = bracketCaculate(strExpression, "{}");
/*************************括号运算结束*****************************/
/*************************单元算式开始*****************************/
//通用单元表达式解析计算
strExpression = UnitExpression.commonUnitExpressionParseCaculate(strExpression);
/*************************单元算式结束*****************************/
return strExpression;
}
/**
* 括号运算
* @author zhuyq
* @date 2020-11-11
*/
public static String bracketCaculate(String strExpression, String bracket){
ArrayList<UnitExpression> unitExpressionList = new ArrayList<>();
//截取所有小中大括号部分,并按UnitExpression格式及顺序存入List
Integer count = StrUtil.countChar(strExpression, bracket.substring(0, 1));
for(int i=0; i<count; i++){
Integer start = StrUtil.getCharacterPosition(strExpression, bracket.substring(0, 1), i+1);
Integer end = StrUtil.getCharacterPosition(strExpression, bracket.substring(1, 2), i+1);
String unitExpressionStr = strExpression.substring(start+1, end);
UnitExpression unitExpression = new UnitExpression(unitExpressionStr, start, end, bracket);
unitExpressionList.add(unitExpression);
}
//小中大括号计算,并替换到四则运算表达式中
StringBuilder strExpressionSb = new StringBuilder(strExpression);
for(int i=0; i<unitExpressionList.size(); i++){
UnitExpression unitExpression = unitExpressionList.get(i);
Integer start = StrUtil.getCharacterPosition(strExpressionSb.toString(), bracket.substring(0, 1), 1);
Integer end = StrUtil.getCharacterPosition(strExpressionSb.toString(), bracket.substring(1, 2), 1);
unitExpression.setStart(start);
unitExpression.setEnd(end);
//通用单元表达式解析计算
String result = UnitExpression.commonUnitExpressionParseCaculate(unitExpression.getUnitExpressionStr());
int position = strExpressionSb.toString().indexOf("("+unitExpression.getUnitExpressionStr()+")");
//特殊情况处理 小括号7+2+(1-10) 2020-12-08
if(unitExpression.getBracket().equals("()") && (new BigDecimal(result)).compareTo(BigDecimal.valueOf(0))==-1 && position>0){
strExpressionSb.replace(unitExpression.getStart()-1, unitExpression.getEnd()+1, result);
}
else{
strExpressionSb.replace(unitExpression.getStart(), unitExpression.getEnd()+1, result);
}
}
strExpression = strExpressionSb.toString();
return strExpression;
}
}
package com.tellhow.czp.netorder.app.nowcoder.huawei.entity;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.tellhow.czp.netorder.app.nowcoder.huawei.util.StrUtil;
/**
* 单元表达式(小/中/大括号里头的表达式和优先级表达式)
* @author zhuyq
* @date 2020-11-11
*/
public class UnitExpression {
String unitExpressionStr; //单元表达式
Integer start; //单元表达式左符号在四则运算表达式字符串定位
Integer end; //单元表达式右符号在四则运算表达式字符串定位
String bracket; //括号(小括号、中括号、大括号)及优先级符号(*/)
public UnitExpression() {
}
public UnitExpression(String unitExpressionStr, Integer start, Integer end, String bracket) {
super();
this.unitExpressionStr = unitExpressionStr;
this.start = start;
this.end = end;
this.bracket = bracket;
}
public String getUnitExpressionStr() {
return unitExpressionStr;
}
public void setUnitExpressionStr(String unitExpressionStr) {
this.unitExpressionStr = unitExpressionStr;
}
public Integer getStart() {
return start;
}
public void setStart(Integer start) {
this.start = start;
}
public Integer getEnd() {
return end;
}
public void setEnd(Integer end) {
this.end = end;
}
public String getBracket() {
return bracket;
}
public void setBracket(String bracket) {
this.bracket = bracket;
}
/**
* 通用单元表达式解析计算
* 方法:先算一级,再算二级
* @author zhuyq
* @date 2020-11-13
*/
public static String commonUnitExpressionParseCaculate(String strExpression){
//单元表达式解析计算--优先级(*/)
strExpression = priorityCaculate(strExpression);
//单元表达式解析计算--无优先级(+-)
strExpression = UnitExpression.unitExpressionParseCaculate(strExpression);
return strExpression;
}
/**
* 优先级(计算*和/,*和/优先级大于+和-,且*和/同优先级)
* 问题:连乘除和同优先级。方法:具体边解析边计算,逻辑或正则表达式 [乘除]。
* 优化:优先级多位数及小数问题。方法:解析添加正则引擎。根据数字[乘或除]数字匹配字符串中第一处。
* 兼容负数问题。方法:正则引擎数字兼容负数。
* @author zhuyq
* @date 2020-11-12
*/
public static String priorityCaculate(String strExpression){
StringBuilder strExpressionSb = new StringBuilder(strExpression);
//截取所有*和/算式部分
Integer count = StrUtil.countChar(strExpression, "*") + StrUtil.countChar(strExpression, "/");
for(int i=0; i<count; i++){
//解析
String regex = "-?(([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9]))[*/]-?(([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9]))";
Matcher slashMatcher = Pattern.compile(regex).matcher(strExpression);
Integer mIdx = 0;
while(slashMatcher.find()) {
mIdx++;
//当regex正则一级运算第1次出现的位置
if(mIdx == 1){
break;
}
}
Integer start = slashMatcher.start();
Integer end = slashMatcher.end();
String unitExpressionStr = strExpression.substring(start, end);
UnitExpression unitExpression = new UnitExpression(unitExpressionStr, start, end, "[*/]");
//计算
String result = UnitExpression.unitExpressionParseCaculate(unitExpression.getUnitExpressionStr());
//特殊情况处理:-0[*/]数或负数[*/]0
String regex1 = "(-0[*/]-?(([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9])))|-(([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9]))[*]0";
Matcher slashMatcher1 = Pattern.compile(regex1).matcher(unitExpressionStr);
if(slashMatcher1.find()){
result = "+0";
}
strExpressionSb.replace(unitExpression.getStart(), unitExpression.getEnd(), result);
strExpression = strExpressionSb.toString();
}
return strExpression;
}
/**
* 单元表达式解析计算, 优先级(无优先级按顺序计算)
* @author zhuyq
* @date 2020-11-11
*/
public static String unitExpressionParseCaculate(String unitExpressionStr){
BigDecimal result = new BigDecimal(0.00);
//ArrayList<Integer> numberList = new ArrayList<>();
ArrayList<String> numberList = new ArrayList<>();
ArrayList<String> symbolList = new ArrayList<>();
//特殊情况:表达式只有一个数字
String resultStr = "";
String regex0 = "-?(([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9]))";
Matcher slashMatcher0 = Pattern.compile(regex0).matcher(unitExpressionStr);
Integer z = -1;
while(slashMatcher0.find()){
z++;
}
if(z==0){
resultStr = unitExpressionStr;
}
else{
/**
* 单元表达式解析,切割数字及符号并按顺序分别存入List
* @version V2.0 [正则解析] 适用正数(多位数、小数)、负数
* @author zhuyq
* @date 2020-11-13
*/
String regex = "-?(([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9]))|[*/+]";
Matcher slashMatcher = Pattern.compile(regex).matcher(unitExpressionStr);
Integer j = -1;
while(slashMatcher.find()) {
String s = unitExpressionStr.substring(slashMatcher.start(), slashMatcher.end());
/**
* 问题:减号与负号冲突
* 方案:减号作负号用,如果数为负数,那么符号symbolList添加"+"
* @date 2020-11-13
*/
if( !(s.equals("*") || s.equals("/") || s.equals("+")) ){
j++;
numberList.add(s);
if( j>0 ){
String str = numberList.get(j-1)+s;
String regex1 = "-?(([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9]))[-](([0-9]\\d*\\.?\\d*)|(0\\.\\d*[0-9]))";
Matcher slashMatcher1 = Pattern.compile(regex1).matcher(str);
if(slashMatcher1.find()){
symbolList.add("+");
}
}
}
else{
symbolList.add(s);
}
}
//单元表达式计算
for(int i=0; i<symbolList.size(); i++){
String symbol = symbolList.get(i);
BigDecimal first = new BigDecimal(0.00);
if( i == 0 ){
first = new BigDecimal(numberList.get(i));
} else{
first = result;
}
BigDecimal second = new BigDecimal(numberList.get(i+1));
result = new BigDecimal( smallUnitCaculate(first, second, symbol ) );
}
resultStr = result.toString();
}
return resultStr;
}
/**
* 小单元运算
* @author zhuyq
* @date 2020-11-11
*/
public static String smallUnitCaculate(BigDecimal first, BigDecimal second, String symbol){
BigDecimal result = new BigDecimal(0.00);
if(symbol.equals("+")){
result = first.add(second);
}
else if(symbol.equals("-")){
result = first.subtract(second);
}
else if(symbol.equals("*")){
result = first.multiply(second);
}
else if(symbol.equals("/")){
if(second.compareTo(BigDecimal.valueOf(0)) == 0){
result = BigDecimal.valueOf(Double.MAX_VALUE);
}
else{
result = first.divide(second, 2, BigDecimal.ROUND_HALF_UP);
}
}
return result.toString();
}
}
package com.tellhow.czp.netorder.app.nowcoder.huawei.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 字符串工具类
* @author zhuyq
* @date 2020-11-13
*/
public class StrUtil {
/**
* 获取指定字符在字符串第n次出现的位置
* @author zhuyq
* @date 2020-11-11
*/
public static Integer getCharacterPosition(String strExpression, String bracket, Integer n){
//这里是获取bracket符号的位置
Matcher slashMatcher;
//括号
if( bracket.equals("(") || bracket.equals(")") || bracket.equals("[") || bracket.equals("]") || bracket.equals("{") || bracket.equals("}") ){
slashMatcher = Pattern.compile("\\"+bracket).matcher(strExpression);
}
//乘除
else{
slashMatcher = Pattern.compile(bracket).matcher(strExpression);
}
Integer mIdx = 0;
while(slashMatcher.find()) {
mIdx++;
//当bracket符号第n次出现的位置
if(mIdx == n){
break;
}
}
return Integer.valueOf(slashMatcher.start());
}
/**
* 统计字符串中指定字符出现的次数
* @author zhuyq
* @date 2020-11-11
*/
public static Integer countChar(String strExpression, String bracket){
Integer count = 0;
for(int i=0; i<strExpression.length(); i++){
if(bracket.equals(String.valueOf(strExpression.charAt(i)))){
count++;
}
}
return count;
}
}

京公网安备 11010502036488号