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() → 高效拼接
相关推荐
风中的微尘8 小时前
39.网络流入门
开发语言·网络·c++·算法
西红柿维生素9 小时前
JVM相关总结
java·jvm·算法
ChillJavaGuy11 小时前
常见限流算法详解与对比
java·算法·限流算法
sali-tec11 小时前
C# 基于halcon的视觉工作流-章34-环状测量
开发语言·图像处理·算法·计算机视觉·c#
你怎么知道我是队长12 小时前
C语言---循环结构
c语言·开发语言·算法
艾醒12 小时前
大模型面试题剖析:RAG中的文本分割策略
人工智能·算法
纪元A梦14 小时前
贪心算法应用:K-Means++初始化详解
算法·贪心算法·kmeans
_不会dp不改名_15 小时前
leetcode_21 合并两个有序链表
算法·leetcode·链表
mark-puls15 小时前
C语言打印爱心
c语言·开发语言·算法