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() → 高效拼接
相关推荐
努力学习的小廉9 分钟前
我爱学算法之—— 字符串
c++·算法
yuuki23323334 分钟前
【数据结构】常见时间复杂度以及空间复杂度
c语言·数据结构·后端·算法
闻缺陷则喜何志丹38 分钟前
【分块 差分数组 逆元】3655区间乘法查询后的异或 II|2454
c++·算法·leetcode·分块·差分数组·逆元
葛小白11 小时前
C#进阶12:C#全局路径规划算法_Dijkstra
算法·c#·dijkstra算法
前端小L1 小时前
图论专题(五):图遍历的“终极考验”——深度「克隆图」
数据结构·算法·深度优先·图论·宽度优先
CoovallyAIHub1 小时前
超越像素的视觉:亚像素边缘检测原理、方法与实战
深度学习·算法·计算机视觉
CoovallyAIHub1 小时前
中科大西工大提出RSKT-Seg:精度速度双提升,开放词汇分割不再难
深度学习·算法·计算机视觉
gugugu.1 小时前
算法:位运算类型题目练习与总结
算法
百***97641 小时前
【语义分割】12个主流算法架构介绍、数据集推荐、总结、挑战和未来发展
算法·架构
代码不停1 小时前
Java分治算法题目练习(快速/归并排序)
java·数据结构·算法