程序员的算法趣题:Q02 数列的四则运算(Java版)

题目说明

在各个数字之间插入四则运算的运算符组成算式,
然后计算算式的结果(某些数位之间可以没有运算符,但整个表达式中最少要插入 1 个运算符)。
例如:
1234 -> 1+2×3-4 = 3
9876 -> 9×87+6 = 789
假设这里的条件是,组合算式的计算结果为“将原数字各个数位上的数逆序排列得到的数”,
并且算式的运算按照四则运算的顺序进行(先乘除,后加减)
那么位于 100~999,符合条件的有以下几种情况。
351 -> 3×51 = 153
621 -> 6×21 = 126
886 -> 8×86 = 688
求:位于 1000~9999,满足上述条件的数。

思路

1.罗列出1000~9999之间的每个数字
2.拆分数字,与运算符组合,拼接成表达式
3.计算表达式的值(①中缀表达式=>后缀表达式(逆波兰表示法) ②计算后缀表达式的值)
4.与第一步罗列出的数字的逆序数字进行比较,如果相等,则输出结果
*5.因为4位数拆成多个数相-,/得到的结果都不足4位;相+若要得到4位数(xxx+x=xxxx),则千位和百位必然是9,又因所求结果为逆序后的数字,所以个位和十位也是9,即999+9=1008,并不符合要求,所以有效的运算符只有

代码

public static void main(String[] args) {
    String[] op = {"+", "-", "*", "/", ""}; // 作为数字之间的分隔符(可根据思路第5步优化为{"*",""})
    // 变量n依次表示指定范围内的每个数字
    for (int n = 1000; n < 10000; n++) { // 四位数中间有3个位置可以插入运算符或者""(不插入)
        String num = "" + n; // 将数字转为字符串形式,以便通过正则表达式拆分
        if (num.matches("\\d*0+$")) continue; // 以0结尾的四位数,反转后不足4位数,直接跳过,从而减少循环次数。
        Double expected = Double.parseDouble(new StringBuilder(num).reverse().toString()); // 反转后的数字:期望值
        
        // 罗列出3个位置上的运算符(或"")
        for (int i = 0; i < op.length; i++) {
            for (int j = 0; j < op.length; j++) {
                for (int k = 0; k < op.length; k++) {
                    // 拼接出算数表达式
                    String exp = num.charAt(0) + op[i] + num.charAt(1) + op[j] + num.charAt(2) + op[k] + num.charAt(3);
                    Double res = getResult(exp); // 计算表达式的值,自定义的方法getResult(xx)
                    // 与期望值比较,相同则输出结果
                    if (Double.compare(expected, res) == 0) { // java.lang.NullPointerException
                        System.out.println(num + " -> " + res); // 最终结果:5931 -> 1395.0
                    }
                }
            }
        }
    }
}
// 按照四则运算优先级,计算表达式的值,并返回
private static Double getResult(String exp) {
    /* 1.中缀表达式 --> 后缀表达式
         1) 通过正则表达式切分算数表达式
         2) 从左往右遍历中缀表达式的每个元素:数字和运算符
         3) 若是数字,直接存入List
         4) 若是符号,则①判断优先级②出栈③入栈:
              i. 判断当前符号与栈顶符号(最近一次存入的符号)的优先级
             ii. 如果该符号是右括号,或者优先级低于栈顶符号,则栈顶元素依次出栈并存入StringBuilder
            iii. 然后将当前符号入栈
         5) 遍历结束后,出栈所有运算符
    */
    Stack nums = new Stack<>(); // 存放数字
    Stack op = new Stack<>(); // 存放符号
    List list = new LinkedList(); // 保存数字和+-*/符号

    // 拆分出数字和操作符
    // \d+(\.\d+)?  表示数字部分,小括号里的是小数部分,?表示0~1次
    // (?
// 四则运算
private static double calc(double pre, double next, String op) {
    switch (op) {
        case "+":
            return pre + next;
        case "-":
            return pre - next;
        case "*":
            return pre * next;
        case "/":
            return pre / next; // Java中两个double相除,0为除数不会报错
        default:
            break;
    }
    throw new IllegalArgumentException("不支持的操作符!");
}
// 计算运算符的优先级。此处指定:数字越大,优先级越高
private static int opPriority(String op) {
    if (op == null) return 0;
    switch (op) {
        case "(":
            return 1;
        case "+":
        case "-":
            return 2;
        case "*":
        case "/":
            return 3;
        default:
            throw new IllegalArgumentException("不支持的操作符!");
    }
}

结果

5931

学习网址

【Java实现四则运算表达式求值(逆波兰法)】https://blog.csdn.net/qq_22795957/article/details/105872740

你可能感兴趣的:(程序员的算法趣题,正则表达式,java,算法)