青训营X豆包MarsCode 技术训练营第五课 | 豆包MarsCode AI 刷题

196 阅读7分钟

题目解析

  • 思路

    • 首先,需要按照题目要求将输入字符串 word 中不是数字的字符替换为空格,这里使用了正则表达式 [^0-9] 通过 replaceAll 方法来实现替换操作,得到一个新的字符串,其中数字部分被保留,其他字符都变为空格了。
    • 接着,由于要统计不同的整数,所以需要把处理后的字符串按照空格进行分割,得到一个个单独的数字字符串组成的数组,使用 trim 方法去除字符串两端可能多余的空格后,再通过 split("\s+") 按照一个或多个连续空格进行分割。
    • 然后,考虑到题目中对于不同整数的定义(不含前导零的十进制表示不同才算不同整数),需要遍历分割得到的数字字符串数组,对每个数字字符串去除前导零,这里利用正则表达式 ^0+(?!$) 通过 replaceFirst 方法来匹配并去除开头连续的 0(但要保证最后剩下的不是空字符串,即排除像 00 这种去除后为空的情况)。
    • 最后,将去除前导零后的非空数字字符串添加到 HashSet 集合中,因为 HashSet 的特性是不允许重复元素,所以最终集合中元素的个数就是不同整数的数量,直接返回这个数量即可。
  • 图解(以示例 a123bc34d8ef34 示意)

    1. 替换非数字字符为空格
      原始字符串 "a123bc34d8ef34",经过 replaceAll("[^0-9]", " ") 操作后,变为 " 123 34 8 34"

    2. 分割字符串
      对 " 123 34 8 34" 使用 trim 去除两端空格后变为 "123 34 8 34",再通过 split("\s+") 按照空格分割,得到字符串数组 ["123", "34", "8", "34"]

    3. 去除前导零并添加到集合

      • 遍历数组,对于 "123",无需去除前导零,直接添加到 HashSet 中。
      • 对于 "34",同样直接添加。
      • 对于 "8",也直接添加。
      • 对于最后一个 "34",同样添加,由于 HashSet 去重特性,重复的 "34" 只会保留一个。
    4. 返回结果
      最终 HashSet 中元素个数为 3,所以返回 3,代表不同整数的数量。

  • 代码详解

收起

java

复制

import java.util.*;

public class Main {

    // 解决方案函数
    public static int solution(String word) {
        // 请在这里编写您的代码
        // 替换非数字字符为空格
        String replaced = word.replaceAll("[^0-9]", " ");
        // 此处使用了Java的正则表达式替换方法replaceAll,它会将字符串word中所有匹配正则表达式"[^0-9]"(即非数字字符)的部分替换为空格,
        // 从而得到一个新的字符串replaced,其中只保留了原字符串中的数字以及它们之间用空格隔开的格式。

        // 分割字符串
        String[] numbers = replaced.trim().split("\s+");
        // 首先调用trim方法去除replaced字符串两端可能存在的多余空格,然后使用split方法,以一个或多个连续空格作为分隔符(正则表达式"\s+"表示),
        // 将字符串分割成一个个单独的数字字符串,存储在numbers数组中。

        // 使用Set来存储不同的整数
        Set<String> uniqueNumbers = new HashSet<>();

        for (String num : numbers) {
            // 去除前导零
            String trimmedNum = num.replaceFirst("^0+(?!$)", "");
            // 使用replaceFirst方法结合正则表达式"^0+(?!$)"来去除字符串num开头连续的0。正则表达式中,"^"表示匹配字符串开头,"0+"表示匹配一个或多个0,
            // "(?!$)"是一个零宽负预测先行断言,表示后面紧接着的不是字符串结尾(也就是保证去除后不是空字符串)。
            if (!trimmedNum.isEmpty()) {
                uniqueNumbers.add(trimmedNum);
                // 如果去除前导零后的字符串trimmedNum不为空,就将其添加到HashSet集合uniqueNumbers中,利用HashSet的元素唯一性特点来统计不同的整数。
            }
        }

        // 返回不同整数的数量
        return uniqueNumbers.size();
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution("a123bc34d8ef34") == 3); // true
        System.out.println(solution("t1234c23456") == 2); // true
        System.out.println(solution("a1b01c001d4") == 2); // true
    }
}

知识总结

  • 新知识点梳理

    • 正则表达式的运用:在本题中多次使用了正则表达式,如 [^0-9] 用于匹配非数字字符,\s+ 用于匹配一个或多个连续空格,^0+(?!$) 用于匹配开头连续的非空的 0。掌握了如何通过正则表达式来灵活地在字符串中查找、替换符合特定模式的字符内容,是处理文本字符串时很强大的工具。
    • HashSet 集合的特性及使用:了解到 HashSet 是基于哈希表实现的集合类,它不允许存储重复元素,利用这个特性可以方便地对数据进行去重处理,在本题中用于统计不同的整数个数,只需将元素添加进去,最后获取集合的大小就是去重后的元素数量。
  • 理解

    • 正则表达式就像是一种文本处理的 “万能钥匙”,通过定义不同的模式规则,可以精准地对字符串进行各种复杂的操作,像筛选、替换特定类型的字符等,大大提高了文本处理的效率和灵活性。而 HashSet 集合则利用其内部的哈希机制实现快速的元素插入和查找,同时保证元素的唯一性,在很多需要去重统计或者判断元素是否重复出现的场景中非常实用。
  • 学习建议(针对入门同学)

    • 对于正则表达式,要先从基础的元字符和语法学起,比如字符类([])、量词(*+? 等)、定位符(^$ 等)的含义和用法,可以通过一些在线的正则表达式练习平台,输入不同的正则表达式和测试字符串,观察匹配结果,逐步熟悉各种模式的编写。同时,多在实际代码中尝试运用正则表达式解决简单的文本处理问题,如提取电话号码、邮箱地址等,加深理解。
    • 在学习 HashSet 集合时,先了解它的基本特点和常用方法(如 addcontainssize 等),通过编写简单的代码示例,比如创建 HashSet 存储一些整数或者字符串,尝试添加重复元素观察结果,以及判断元素是否存在等操作,感受其去重功能。然后可以结合实际应用场景,如统计班级学生的不同姓名数量、不同考试成绩的个数等,用 HashSet 来实现,进一步掌握其使用方法。

学习计划

  • 制定刷题计划

    • 入门基础阶段

      • 以字符串处理、基本集合操作相关的简单题目为开始,例如在 LeetCode 等刷题平台上筛选出这类标签下的简单难度题目。每天安排 1 - 2 小时,刷 2 - 3 道题,重点关注题目中涉及的知识点运用,像本题中的字符串替换、分割以及集合去重操作等,把每道题涉及的基础知识点都理解透彻,代码实现要保证逻辑清晰、语法正确。
      • 在刷题过程中,对于不熟悉的 API(如字符串的各种方法、集合类的方法等)及时查阅官方文档,了解其参数、返回值及使用场景,做好笔记记录。每做完几道题后,总结一下相同知识点在不同题目中的不同运用方式,加深印象。
    • 巩固提升阶段

      • 增加题目难度,选择涉及多个知识点综合运用的中等难度题目,比如字符串处理与排序算法结合、集合操作与循环嵌套等类型的题目。每周抽出 3 - 4 天,每天安排 2 - 3 小时刷题,每次刷题量可以在 3 - 5 道题左右。
      • 这个阶段除了完成代码实现外,要注重分析题目解题思路的形成过程,尝试从不同角度思考解法,对于做错的题目,详细分析错误原因,是知识点掌握不扎实还是解题思路有误,整理错题笔记,同时回顾相关知识点进行强化学习,并且找一些类似错题的题目进行巩固练习。
    • 拓展深化阶段

      • 挑战高难度的题目,特别是那些在实际面试或者算法竞赛中常出现的难题,以及具有创新性、综合性很强的题目。可以参加一些线上的刷题社区或者算法学习小组,和其他同学一起讨论难题解法,互相分享思路。
      • 针对难题,深入研究其背后的算法原理和优化思路,尝试自己对题目进行变形、拓展,探索更多的解法可能性,通过这种方式拓宽自己的思维视野,完善知识体系,同时将错题整理成详细的案例分析,定期回顾复习,确保对难题也能掌握扎实。
  • 利用错题进行针对性学习

    • 错题整理与分析:将做错的题目按照知识点模块和错误类型进行分类整理,比如本题可以归到字符串处理和集合运用相关的错题中。详细记录题目内容、自己的错误解法、正确解法以及出错的具体原因,例如是正则表达式编写错误、对 HashSet 去重原理理解不清等,标注出涉及的知识点漏洞。
    • 知识点复习与强化:根据错题分析出的知识点漏洞,重新系统学习对应的知识内容,可以通过查阅教材、观看线上课程讲解等方式进行。比如错题是因为正则表达式不熟悉导致的,就重新学习正则表达式的语法和常见应用案例,然后找一些针对性的练习题进行专项训练,巩固所学知识,直到能够正确运用到类似题目中为止。
    • 举一反三与拓展:在掌握错题的正确解法后,思考这道题涉及的知识点还能如何在其他题目场景中运用,尝试对题目进行变形,自己出题并解答,例如改变本题中字符串的格式或者不同整数的判断条件等,通过这种方式加深对知识点的理解深度和运用的灵活性,真正做到举一反三。

工具运用

  • 与在线教程配合:在使用 AI 刷题时,结合一些优质的在线编程教程网站,如菜鸟教程、W3School 等。当遇到不熟悉的知识点(比如本题中的正则表达式或 HashSet 集合相关知识),可以先在这些教程网站上查找对应的详细讲解,学习基础知识、语法和常见示例,构建起基本的知识框架,然后再通过 AI 刷题来实践运用这些知识,遇到问题再返回教程进一步查漏补缺,形成一个良性的学习循环。
  • 与开源代码学习结合:在 GitHub 等平台上搜索一些开源的 Java 项目,尤其是那些涉及大量字符串处理和数据管理(会用到集合类)的项目,下载并阅读其代码。观察在实际项目中是如何运用字符串操作方法、正则表达式以及集合类来解决具体问题的,比如在一个文本分析项目中如何提取有效信息、去重统计等,通过学习开源代码中的优秀实践,加深对所学知识的理解,同时也能了解到这些知识在实际开发场景中的应用规范和技巧,提高自己的编程能力。
  • 与论坛交流互动:参与技术论坛(如 Stack Overflow、掘金等)的相关讨论区,在刷题过程中遇到难题或者对某个知识点有疑问时,将问题发布到论坛上,向广大开发者请教,参考别人的回答和思路,拓宽自己的思维方式。同时,也可以分享自己通过 AI 刷题总结出的解题技巧、知识点总结等内容,与其他学习者互相交流学习,从不同角度加深对知识的理解和掌握,提升学习效果。