import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class 数列的四则运算 {
public static void main(String[] args) throws Exception {
// 运算符号,最后一个为空代表没有运算符
String[] ops = new String[]{"+","-","*","/",""};
// String[] ops = new String[]{"*",""};
for(int i = 1000; i <= 9999; i++) {
String num = i + "";
for (String value : ops) {
for (String s : ops) {
for (String op : ops) {
String operation = num.charAt(0) + value + num.charAt(1) + s + num.charAt(2) + op + num.charAt(3);
if (operation.length() > 4) {
List<String> list = toList(operation);
List<String> suffix = centerToAfter(list);
StringBuilder result = new StringBuilder(Calculate(suffix)).reverse();
if (result.toString().equals(num)) {
System.out.println("num = " + num);
System.out.println("operation = " + operation);
System.out.println("list = " + list);
System.out.println("suffix = " + suffix);
System.out.println("result = " + result);
System.out.println("-------------------------------");
}
}
}
}
}
}
}
// 将字符串用list装起来
public static List<String> toList(String operation) {
List<String> list = new ArrayList<>();
char c;
String keepNum;
for(int i = 0; i < operation.length(); i++) {
if(!Character.isDigit(c = operation.charAt(i))) {
list.add(Character.toString(c));
}else {
keepNum = "";
while (i < operation.length() && Character.isDigit(c = operation.charAt(i))) {
keepNum += c;
i++;
}
i--;
list.add(keepNum);
}
}
return list;
}
// 将中缀表达式变为后缀表达式
public static List<String> centerToAfter(List<String> list) throws Exception {
Stack<String> stringStack = new Stack<>();
// 用list就已经相当与栈的逆序了
List<String> stringList = new ArrayList<>();
for(String item : list) {
if(item.matches("\\d+")) {
stringList.add(item);
}else {
if(stringStack.isEmpty()) {
stringStack.push(item);
}else {
while (!stringStack.isEmpty() && priority(stringStack.peek()) >= priority(item)) {
stringList.add(stringStack.pop());
}
stringStack.push(item);
}
}
}
while (!stringStack.isEmpty()) {
stringList.add(stringStack.pop());
}
return stringList;
}
// 通过后缀表达式进行计算值
public static String Calculate(List<String> list) {
Stack<String> stack = new Stack<>();
for(String item : list) {
if(item.matches("\\d+")) {
stack.push(item);
}else {
double num1 = Double.parseDouble(stack.pop());
double num2 = Double.parseDouble(stack.pop());
double result = 0;
switch (item) {
case "+": result = num1 + num2; break;
case "-": result = num2 - num1; break;
case "*": result = num1 * num2; break;
case "/": result = num2 / num1; break;
default:
System.out.println("运算符错误");
}
stack.push((int) result + "");
}
}
return stack.peek();
}
// 比较运算符优先级
public static int priority(String operator) throws Exception {
if(operator.equals("+") || operator.equals("-")) {
return 1;
}else if(operator.equals("*") || operator.equals("/")) {
return 2;
}else {
System.out.println("不存在该运算符");
}
return 0;
}
}
解题思路
首先第一步,肯定要将一个数字和运算符的所有组合给排列出来,然后根据式子去计算结果,在和原来的数据进行比较即可,这里用到了关于表达式的算法问题,前缀表达式,后缀表达式(逆波兰表达式),中缀表达式,顺带复习一下
首先我们得到的式子肯定是中缀表达式,但中缀表达式不利于计算进行计算,所有需要将中缀表达式转为后缀表达式,转的步骤为:
1.初始化两个栈,运算符栈s1和存储中间结果栈s2
2.从左到右扫描中缀表达式
3.遇到操作数时,将操作数压入到s2
4.遇到运算符时,比较其与栈顶运算符的优先级:
1.如果s1为空,或者栈顶运算符为“(”,则直接压入
2.否则,若优先级比栈顶运算符高,也将运算符压入s1
3.否则,优先级比栈顶运算符低,s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符比较
5.遇到括号时:
1.如果是左括号,直接压入s1
2.如果是右括号,则一次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
6.重复步骤2-5,直到表达式最右边
7.将s1中剩余的运算符依次弹出并压入s2
8.依次弹出s2中的元素并输出,结果的*逆序*即为中缀表达式对应的后缀表达式
_括号并不算运算符_
这里不考虑括号的情况,所以代码会简单一些
其次将得到的后缀表达式进行算数运算,运算步骤为:
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数
用运算符对他们做相应的计算,用后面的数对前面的数进行运算,
并将结果入栈,重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果
这里顺带提一下关于前缀表达式的计算步骤
1.从右至左进行扫描,将数字6543压入堆栈
2.遇到+运算符时,弹出栈中元素3和4,计算3+4的值得7,在将7压入栈
3.遇到*运算符时,弹出5和7,计算得35压入栈
4.最后-运算符,计算35-6的值,得出最终结果