当前位置:   article > 正文

华为OD 提取字符串中最长数学表达式(通过88.9%的测试用例) Java_提取字符串中的最长合法简单数学表达式,字符串长度最长的,并计算表达式的值。如果

提取字符串中的最长合法简单数学表达式,字符串长度最长的,并计算表达式的值。如果

题目描述

提取字符串中的最长合法简单数学表达式,字符串长度最长的,并计算表达式的值。如果没有,则返回0。简单数学表达式只能包含以下内容:0-9数字,符号 +-*

说明:

  1. 所有数字,计算结果都不超过long
  2. 如果有多个长度一样的,请返回第一个表达式的结果
  3. 数学表达式,必须是最长的,合法的
  4. 操作符不能连续出现,如 *-+1 是不合法的

输入

字符串

输出

表达式值

示例

输入:
1-2abcd

输出:
-1

Java代码(通过88.9%的测试用例)

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    private static final String v = "0123456789+-*";

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        List<String> formulas = new ArrayList<>();
        char[] chars = str.toCharArray();
        
        // 提取可能的合法表达式
        for (int i = 0; i < str.length(); i++) {
            char c = chars[i];
            if (Character.isDigit(c)) {
                int start = i;
                while (i + 1 < chars.length && v.contains(chars[i + 1] + "")) {
                    if (!Character.isDigit(chars[i]) && !Character.isDigit(chars[i + 1]) && chars[i + 1] != '-') {
                        break;
                    }
                    i++;
                }
                if (!Character.isDigit(str.charAt(i))) {
                    formulas.add(str.substring(start, i));
                } else {
                    formulas.add(str.substring(start, i + 1));
                }
            }
        }

		// 按长度排序,找到最长的表达式
        Collections.sort(formulas, (f1, f2) -> Integer.compare(f2.length(), f1.length()));
        if (formulas.size() > 0) {
            String res = calculateFormula(formulas.get(0));
            System.out.println(res);
        } else {
            System.out.println(0);
        }

    }

	/**
     * 计算给定表达式的值
     * @param formula 数学表达式字符串
     * @return 表达式的计算结果
     */
    private static String calculateFormula(String formula) {
        char[] chars = formula.toCharArray();
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < chars.length; i++) {
            if (Character.isDigit(chars[i])) {
                builder.append(chars[i]);
            } else if (!Character.isDigit(chars[i]) && i != chars.length - 1) {
                builder.append(",").append(chars[i]).append(",");
            }
        }
        List<String> list = Stream.of(builder.toString().split(",")).collect(Collectors.toList());
        
        // 处理每个数字,以应对例如:"0200"的情况,将其转化为:"200"
        for (int i = 0; i < list.size(); i++) {
            if (!list.get(i).equals("+") && !list.get(i).equals("*") && !list.get(i).equals("-")) {
                long num = Long.parseLong(list.get(i));
                list.set(i, num + "");
            }
        }
        if (list.size() == 1) {
            return list.get(0);
        }

		// 先计算乘法,再计算加减
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).equals("*")) {
                calculate(list, i, "*");
                i = 0;
            }
        }
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).equals("+")) {
                calculate(list, i, "+");
                i = 0;
            }
            if (i < list.size() && list.get(i).equals("-")) {
                calculate(list, i, "-");
                i = 0;
            }
        }

        return list.get(0);
    }

    private static void calculate(List<String> list, int i, String op) {
        long a = Long.parseLong(list.get(i - 1));
        long b = Long.parseLong(list.get(i + 1));
        long res = 0L;
        switch (op) {
            case "*":
                res = a * b;
                break;
            case "+":
                res = a + b;
                break;
            case "-":
                res = a - b;
                break;
        }
        list.set(i, res + "");
        list.remove(i-1);
        list.remove(i);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

问题总结

1. 代码参考:题目0124-最长合法表达式

尽管参考,但建议各位不要全数抄写参考的代码,因为里面的问题还是不少的,需要注意判别,例如:

  1. 在判断表达式是否合法的条件上设置错误
    // 判断条件:操作符不能连续出现
    // 错误❌
    if (!Character.isDigit(cur) && !Character.isDigit(chars[i + 1])) {
    	break;
    }
    // 正确✔
    if (!Character.isDigit(chars[i]) && !Character.isDigit(chars[i + 1])) {
    	break;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  2. 没有处理可能的表达式最后一个字符是否为操作符的情况

2. 为什么不使用正则表达式 regex = "[0-9+\\-*]+"

因为如果使用正则表达式regex,将输入的字符串 str 通过 str = str.replaceAll(regex, ""),会删去字符串中非0-9数字以及符号 ±*外的其他字符,但是这也会导致一些问题,例如:当我们输入:1+2+3abc45+1 时,如果采用正则表达式的方式,会导致获取的最长表达式为:1+2+345+1,但是这明显是不对的,而通过判断各个字符是否符合标准的方式则得到的最长表达式为:1+2+3

3. 处理可能字符串的最后一个字符

在代码中有如此一段:

if (!Character.isDigit(str.charAt(i))) {
	formulas.add(str.substring(start, i));
} else {
	formulas.add(str.substring(start, i + 1));
}
  • 1
  • 2
  • 3
  • 4
  • 5

这是因为在判断可能存在的字符串时使用的条件是:没有连续的操作符
但是在判断例如:1+2+3+ 的表达式时,就没办法正确处理最后一个字符,最后保存的表达式可能就是 1+2+3+ ,这明显不正确,因此设置 if 条件来处理可能的表达式。

4. 为什么在 calculateFormula 中将 String 类型的数值转换为 Long 类型?

具体代码:

for (int i = 0; i < list.size(); i++) {
	if (!list.get(i).equals("+") && !list.get(i).equals("*") && !list.get(i).equals("-")) {
		long num = Long.parseLong(list.get(i));
		list.set(i, num + "");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这是因为在测试用例中有输入类似: 0200 的情况,这样输出的结果为:0200,不符合要求,故进行处理。
注意:在遇到 0200 + 1 的情况无论有无这段代码都不会出现 0201 的情况。

5. 为什么只通过了88.9%的测试用例?

这是因为测试用例本身就有问题,在测试用例中有如此两个用例:
用例编号: test_16
用例一: -02
预期输出: 0

用例编号: test_15
用例二: 12345
预期输出: 12345

这两个用例之间存在逻辑矛盾,对于 -02 ,如果理想算法认为负数合法的话,预期输出应为: -2 ,但是并不是,这说明在判断表达式是否合法的条件上有一条,即:操作符的两侧必有数字以构成表达式,否则非法;同时,也说明了不能将数值单独作为表达式,否则的话预期输出就应当为:2。但是,很明显的是,结合用例二,我们可以知道单独的数值也能作为表达式,如此一来,两个用例之间自相矛盾,无法同时处理。

测试

OJ算法

题目编号结果内存时间语言代码长度
3005答案错误 AC:88.9%36904 KiB2248 msJava/Edit4619 bytes

侵权必删声明
本资料部分内容来源于互联网及公开渠道,仅供学习和交流使用,版权归原作者所有。若涉及版权问题,敬请原作者联系我,我将立即处理或删除相关内容。感谢您的理解与支持。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/977928
推荐阅读
相关标签
  

闽ICP备14008679号