LeetCode每日一题,20250914

元音拼写检查器

思路

  1. 精确匹配

    • HashSet 保存原始单词,查询时直接判断是否存在。
  2. 大小写忽略匹配

    • HashMap<String, String> 保存 小写单词 -> 第一次出现的原始单词
    • putIfAbsent,确保只记录第一次出现的单词。
  3. 元音模糊匹配

    • 把单词里所有元音替换为 *,得到模糊形式。
    • HashMap<String, String> 保存 模糊形式 -> 第一次出现的原始单词
    • 查询时同样先转小写再模糊化,然后查表。

查询优先级

  • 精确匹配 → 大小写匹配 → 元音模糊匹配 → 否则返回 ""
java 复制代码
class Solution {

    String vowels = "aeiou";

    public String[] spellchecker(String[] wordlist, String[] queries) {
        Set<String> wordSet = new HashSet<>();             // 精确匹配
        Map<String, String> caseMap = new HashMap<>();     // 忽略大小写
        Map<String, String> vowelMap = new HashMap<>();    // 忽略元音

        // 预处理 wordlist
        for (String word : wordlist) {
            wordSet.add(word);

            String lower = word.toLowerCase();
            caseMap.putIfAbsent(lower, word);

            String devoweled = devowel(lower);
            vowelMap.putIfAbsent(devoweled, word);
        }

        String[] ans = new String[queries.length];

        // 查询
        for (int i = 0; i < queries.length; i++) {
            String query = queries[i];

            if (wordSet.contains(query)) {  // 精确匹配
                ans[i] = query;
            } else {
                String lower = query.toLowerCase();

                if (caseMap.containsKey(lower)) {  // 大小写匹配
                    ans[i] = caseMap.get(lower);
                } else {
                    String devoweled = devowel(lower);
                    ans[i] = vowelMap.getOrDefault(devoweled, "");
                }
            }
        }

        return ans;
    }

    // 把所有元音替换成 '*'
    private String devowel(String word) {
        StringBuilder sb = new StringBuilder();
        for (char c : word.toCharArray()) {
            if (vowels.indexOf(c) != -1) {
                sb.append('*');
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}

方法二,用stream流

明白了,我帮你重整理,把 devowel 函数相关的语法(3,4,5)归为一个类,同时去掉 6,7。这样笔记更清晰、针对性更强。


java 复制代码
import java.util.*;
import java.util.stream.*;

class Solution {
    private final String vowels = "aeiou";

    public String[] spellchecker(String[] wordlist, String[] queries) {
        // 精确匹配
        Set<String> wordSet = new HashSet<>(Arrays.asList(wordlist));

        // 大小写忽略,保存第一次出现的原始单词
        Map<String, String> caseMap = Arrays.stream(wordlist)
                .collect(Collectors.toMap(
                        w -> w.toLowerCase(),
                        w -> w,
                        (oldVal, newVal) -> oldVal   // 保证第一次出现
                ));

        // 元音忽略,保存第一次出现的原始单词
        Map<String, String> vowelMap = Arrays.stream(wordlist)
                .collect(Collectors.toMap(
                        w -> devowel(w.toLowerCase()),
                        w -> w,
                        (oldVal, newVal) -> oldVal   // 保证第一次出现
                ));

        // 查询处理(用 stream 映射)
        return Arrays.stream(queries)
                .map(q -> {
                    if (wordSet.contains(q)) {
                        return q; // 精确匹配
                    }
                    String lower = q.toLowerCase();
                    if (caseMap.containsKey(lower)) {
                        return caseMap.get(lower); // 忽略大小写
                    }
                    return vowelMap.getOrDefault(devowel(lower), ""); // 忽略元音
                })
                .toArray(String[]::new);
    }

    // 把元音替换成 *
    private String devowel(String word) {
        return word.chars()
                .mapToObj(c -> vowels.indexOf(c) != -1 ? "*" : String.valueOf((char) c))
                .collect(Collectors.joining());
    }
}

代码解析

1️⃣ 数组和 List 的区别

java 复制代码
Set<String> wordSet = new HashSet<>(Arrays.asList(wordlist));
  • wordlist数组 (String[])
  • HashSet 构造函数需要 Collection 类型(List/Set 等),数组本身不是 Collection
  • Arrays.asList(wordlist) → 把数组转成 List,方便初始化 Set
特性 数组 (String[]) List (List<String>)
大小 固定 可变
方法 .length add, remove, contains 等
接口 不实现 Collection 实现 Collection
可作为构造参数 不可以 可以

2️⃣ Stream + Collectors.toMap(构建 Map)

java 复制代码
Map<String, String> caseMap = Arrays.stream(wordlist)
    .collect(Collectors.toMap(
        w -> w.toLowerCase(),      // key 映射规则
        w -> w,                    // value 映射规则
        (oldVal, newVal) -> oldVal // key 冲突时保留第一次出现
    ));
  • Arrays.stream(wordlist) → 把数组转成 Stream
  • Collectors.toMap(keyMapper, valueMapper, mergeFunction)
参数 作用
keyMapper Stream 元素如何生成 key (w -> w.toLowerCase())
valueMapper Stream 元素如何生成 value (w -> w)
mergeFunction key 冲突时如何处理 (oldVal, newVal) -> oldVal → 保留第一次出现

示例

java 复制代码
wordlist = {"KiTe", "kite", "Hare"}
Map -> {"kite" -> "KiTe", "hare" -> "Hare"}
  • 保证第一次出现的单词被记录,不被后续重复覆盖

3️⃣ devowel 函数解析(字符流 + 拼接)

java 复制代码
private String devowel(String word) {
    return word.chars()
            .mapToObj(c -> vowels.indexOf(c) != -1 ? "*" : String.valueOf((char) c))
            .collect(Collectors.joining());
}
3.1 word.chars()
  • 将字符串拆成 IntStream
  • 每个字符是 Unicode 编码的 int
  • 示例:
java 复制代码
"Hi".chars() -> 72, 105
3.2 String.valueOf((char) c)
  • chars() 返回的是 int
  • (char) c → 把 int 转回字符
  • String.valueOf(char) → 把字符变成长度为 1 的字符串
  • 用于最终拼接
3.3 Collectors.joining()
  • 将 Stream 中的每个字符串 拼接成一个完整字符串
  • 内部使用 StringBuilder,不会像 s += c 那样每次循环都生成新对象
  • 高效拼接字符串

总结 devowel 技巧

  1. word.chars() → 拆成字符流
  2. (char) c + String.valueOf() → 字符转换成字符串
  3. Collectors.joining() → 高效拼接
相关推荐
庞轩px6 分钟前
MinorGC的完整流程与复制算法深度解析
java·jvm·算法·性能优化
Queenie_Charlie12 分钟前
Manacher算法
c++·算法·manacher
闻缺陷则喜何志丹13 分钟前
【树的直径 离散化】 P7807 魔力滋生|普及+
c++·算法·洛谷·离散化·树的直径
AI_Ming20 分钟前
Seq2Seq-大模型知识点(程序员转行AI大模型学习)
算法·ai编程
若水不如远方26 分钟前
分布式一致性(六):拥抱可用性 —— 最终一致性与 Gossip 协议
分布式·后端·算法
计算机安禾30 分钟前
【C语言程序设计】第35篇:文件的打开、关闭与读写操作
c语言·开发语言·c++·vscode·算法·visual studio code·visual studio
Wect39 分钟前
React Hooks 核心原理
前端·算法·typescript
美式请加冰1 小时前
字符串的介绍和使用
算法
m0_733612211 小时前
C++20概念(Concepts)入门指南
开发语言·c++·算法
仰泳的熊猫1 小时前
题目2571:蓝桥杯2020年第十一届省赛真题-回文日期
数据结构·c++·算法·蓝桥杯