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() → 高效拼接
相关推荐
AI视觉网奇2 小时前
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr
开发语言·c++·算法
ghie90903 小时前
ECG波形检查与分析系统
算法
智者知已应修善业3 小时前
【输入两个数字,判断两数相乘是否等于各自逆序数相乘】2023-10-24
c语言·c++·经验分享·笔记·算法·1024程序员节
测试秃头怪3 小时前
2026最新软件测试面试八股文(含答案+文档)
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
Shingmc33 小时前
【Linux】进程控制
linux·服务器·算法
阿正的梦工坊4 小时前
DreamGym:通过经验合成实现代理学习的可扩展化
人工智能·算法·大模型·llm
小武~4 小时前
Leetcode 每日一题C 语言版 -- 45 jump game ii
c语言·算法·leetcode
行云流水6264 小时前
前端树形结构实现勾选,半勾选,取消勾选。
前端·算法
laocooon5238578865 小时前
一个C项目实现框架
c语言·算法
大吱佬6 小时前
面试记录自用
面试·职场和发展