找出 TOP 3 的数字

104 阅读3分钟

找出 TOP 3 的数字

目标

从一个包含字母、数字和各种符号的混合字符串中,抽取出所有有效的整数,并找出其中值最大的前三个。

数字抽取规则

在解析字符串时,一个有效的“整数”必须遵循以下规则:

  1. 完整性: 整数必须被完整地抽取。一个连续的数字序列应被视为一个单独的数字。

    • 例如:在 "a-132b" 中,应抽取出整数 -132,而不是 -1, 3, 232
  2. 负号识别: 一个负号 '-' 后面紧跟着一个或多个数字时,应被视为一个负数。

    • 例如:"-6" 抽取出 -6
    • 例如:"@$-a" 中的 '-' 后面不是数字,它只是一个普通的分隔符,不构成负数。
  3. 前导零处理: 输入的数字可能包含前导零(例如 01, -007)。在解析其数值时需要正确处理(例如,"01" 的数值是 1"-007" 的数值是 -7)。

  4. 分隔符: 任何非数字字符(且不满足上述负号规则)都可视为数字之间的分隔符。

任务要求

  1. 抽取 (Extract): 从输入字符串 inputStr 中,根据【数字抽取规则】找出所有整数。
  2. 排序 (Sort): 将所有抽出的整数按值大小进行降序排列。
  3. 筛选 (Select): 选取排序后列表中的前三个数。如果抽取的整数总数不足三个,则取所有抽出的整数。

解答要求

  • 时间限制: 1000ms
  • 内存限制: 256MB

输入格式

  • 一个字符串参数 inputStr

    • 1 <= inputStr.length <= 1000
    • 仅包含可见字符(ASCII 码值 32 到 126)。
    • 用例保证字符串中至少包含一个数字。
    • 所包含数字的数值范围在 [-2^31, 2^31 - 1] 内(即 Java int 范围内)。

输出格式

  • 一个降序排列的整数序列,最多包含三个元素。

样例

输入样例 1

"a56b-6-8()_56!@$-a"

输出样例 1

[56, 56, -6]

样例 1 解释:

  1. 输入字符串: "a56b-6-8()_56!@$-a"

  2. 抽取过程:

    • 遇到 '5',开始解析数字,得到 56
    • 遇到 '-',其后是 '6',解析为负数 -6
    • 遇到 '-',其后是 '8',解析为负数 -8
    • 遇到 '5',开始解析数字,得到 56
    • 遇到 '-',其后是 'a',不是数字,因此 '-' 仅为分隔符。
  3. 抽取的整数列表: [56, -6, -8, 56]

  4. 降序排序: [56, 56, -6, -8]

  5. 取前三: 最终结果为 [56, 56, -6]


输入样例 2

"--028.300003"

输出样例 2

[300003, -28]

解释:

  1. 输入字符串: "--028.300003"

  2. 抽取过程:

    • 第一个 '-' 后面是另一个 '-',不是数字,因此第一个 '-' 是分隔符。
    • 第二个 '-' 后面是 '0',开始解析负数,"-028" 的数值为 -28
    • '.' 是分隔符。
    • 遇到 '3',开始解析数字,得到 300003
  3. 抽取的整数列表: [-28, 300003]

  4. 降序排序: [300003, -28]

  5. 取前三: 由于总数不足三个,取所有抽出的数,结果为 [300003, -28]

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 实现一个从字符串中抽取最大的三个整数的系统.
 */
public class Top3Extractor {
    /**
     * 主方法,从输入字符串中抽取最大的三个整数.
     * @param inputStr 包含可见字符的输入字符串
     * @return 按值大小降序排列的最多三个整数的列表
     */
    public List<Integer> extractTop3(String inputStr) {

        // --- 步骤 1: 使用正则表达式抽取所有符合条件的数字字符串 ---

        List<Integer> extractedNumbers = new ArrayList<>();

        // 定义正则表达式模式:
        // -?   : 匹配一个可选的'-'字符 (用于负数)
        // \d+ : 匹配一个或多个数字字符 ('0'-'9')
        // 这个模式可以匹配出所有独立的整数,例如 "56", "-6", "-028"
        String regex = "-?\d+";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(inputStr);

        // 使用 Matcher.find() 循环查找所有匹配项
        while (matcher.find()) {
            // matcher.group() 获取当前匹配到的字符串
            String numberStr = matcher.group();
            
            // --- 步骤 2: 将抽取的字符串转换为整数并存储 ---
            try {
                // Integer.parseInt() 会自动处理负号和前导零。
                // 例如,"-028" 会被正确解析为 -28。
                int number = Integer.parseInt(numberStr);
                extractedNumbers.add(number);
            } catch (NumberFormatException e) {
                // 题目保证数字范围在int内,但作为健壮性代码,可以捕获异常。
                // 在本题场景下可以忽略此异常。
            }
        }

        // --- 步骤 3: 对所有抽取的整数进行降序排序并选取前三 ---

        // 使用 Stream API 进行排序和筛选:
        // 1. .stream()              : 创建一个流
        // 2. .sorted(...)           : 进行排序。Comparator.reverseOrder() 指定降序。
        // 3. .limit(3)              : 只取排序后的前3个元素。如果总数少于3,则取所有。
        // 4. .collect(Collectors.toList()) : 将结果收集到一个新的列表中。
        return extractedNumbers.stream()
                .sorted(Comparator.reverseOrder())
                .limit(3)
                .collect(Collectors.toList());
    }
}