中文分词模拟器

一、题目描述

给定一个连续不包含空格的字符串,该字符串仅包含英文小写字母及英文标点符号(逗号、分号、句号),同时给定词库,对该字符串进行精确分词。

说明:

  1. 精确分词:字符串分词后,不会出现重叠。即"ilovechina",不同词库可分割为"i,love,china","ilove,china",不能分割出现重叠的"i,ilove,china",i 出现重叠

  2. 标点符号不成词,仅用于断句

  3. 词库:根据外部知识库统计出来的常用词汇例:dictionary = ["i", "love", "china", "lovechina", "ilove"]

  4. 分词原则:采用分词顺序优先且最长匹配原则

    "ilovechina",假设分词结果 [i,ilove,lo,love,ch,china,lovechina],则输出 [ilove,china]

    错误输出:[i,lovechina],原因:"ilove" > 优先于 "lovechina" 成词

    错误输出:[i,love,china],原因:"ilove" > "i"遵循最长匹配原则

二、输入输出描述

输入描述

  • 第一行:待分词语句,连续无空格,0 < length < 256
  • 第二行:词库字符串,以逗号分隔,1 < length < 100000

输出描述

  • 按分词顺序输出结果,词汇以逗号分隔;
  • 若某段字符无匹配词汇(标点除外),则该段不输出(或按实际匹配结果)

三、示例

|----|------------------------------------------------------|
| 输入 | ilovechina i,love,china,ch,na,ve,lo,this,is,the,word |
| 输出 | i,love,china |
| 说明 | |

|----|----------------------------------------------------------------|
| 输入 | iat i,love,china,ch,na,ve,lo,this,is,the,word,beauti,tiful,ful |
| 输出 | i,a,t |
| 说明 | 单个字母, 不在词库中且不成词则输出单个字母 |

|----|------------------------------------------------------------------------------------------|
| 输入 | ilovechina,thewordisbeautiful i,love,china,ch,na,ve,lo,this,is,the,word,beauti,tiful,ful |
| 输出 | i,love,china the,word,is,beauti,ful |
| 说明 | 标点符号为英文标点符号 |

四、解题思路

  1. 核心思想

最长匹配 + 顺序处理 + 词汇单次消耗为核心,通过队列维护待分词片段,对每个片段从最长长度开始尝试匹配词库,优先选用最长匹配的词汇(保证分词粒度最大化),匹配失败则拆分单个字符,同时词库词汇匹配后立即移除(避免重复使用),最终按顺序输出分词结果。

  1. 问题本质分析
  • 表层问题:将待分词句子按词库拆分,输出指定格式的分词结果;
  • 深层问题:
    1. 分词的 "最优匹配":自然语言分词中,最长匹配是最基础且有效的策略(避免过度拆分,如 "中国" 拆成 "中"+"国");
    2. 顺序约束:必须按原文顺序分词,因此从片段起始位置开始截取子串;
    3. 资源消耗:词库词汇是 "有限资源",单次使用后需移除,保证每个词汇仅参与一次匹配;
    4. 边界处理:无匹配词汇时的兜底逻辑(拆分单个字符),保证分词过程不中断。
  1. 核心逻辑
  • 数据结构选型:用 HashSet 存储词库(快速查找 / 删除),用 LinkedList 模拟队列(按顺序处理待分词片段);
  • 最长匹配:对每个待分词片段,从最大长度到 1 截取子串,找到第一个匹配的词库词汇即选用;
  • 状态维护:匹配成功则更新结果和词库,剩余片段重回队列;匹配失败则拆分首字符,剩余片段重回队列;
  • 结果拼接:将分词结果按顺序拼接为逗号分隔的字符串。
  1. 步骤拆解

  2. 输入预处理

    • 将待分词句子、词库按,.;拆分,转为字符串数组;
    • 词库数组转 HashSet(wordSet),支持快速查找和删除;
    • 待分词句子数组转入队列(queue),保证处理顺序。
  3. 循环处理待分词片段当队列非空时,重复以下步骤:

    • 取出队首的待分词片段(sentence);
    • 最长匹配尝试:从r = 片段长度开始递减,截取[0, r)的子串:① 若子串在wordSet中:将子串加入结果,从wordSet移除该词汇;若有剩余片段,放回队首;退出循环;② 若遍历完所有长度(r=0):将片段第一个字符加入结果,剩余片段放回队首。
  4. 结果拼接与返回

    • 将结果集合(ans)用逗号分隔拼接为字符串;
    • 返回拼接后的字符串。

五、代码实现

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

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    String[] sentences = sc.nextLine().split("[,.;]");
    String[] words = sc.nextLine().split("[,.;]");

    System.out.println(getResult(sentences, words));
  }

  public static String getResult(String[] sentences, String[] words) {
    // wordSet 记录词库词汇
    HashSet<String> wordSet = new HashSet<>(Arrays.asList(words));

    // queue记录待分词语句
    LinkedList<String> queue = new LinkedList<>(Arrays.asList(sentences));

    // ans记录最终分词结果
    LinkedList<String> ans = new LinkedList<>();

    while (queue.size() > 0) {
      // 待分词的句子
      String sentence = queue.removeFirst();

      int r = sentence.length();
      for (; r > 0; r--) {
        // 截取句子 [0,r) 范围子串词汇, 这样的就能实现优先最长匹配,并且由于是必须从0索引开始截取,因此满足了分词顺序优先
        String fragment = sentence.substring(0, r);

        // 若词库中是否存在该子串词汇
        if (wordSet.contains(fragment)) {
          // 则将对应子串词汇纳入结果
          ans.addLast(fragment);
          wordSet.remove(fragment); // 我理解词库中每个词汇只能使用一次,因此这里将词库中使用过的词汇移除

          // 若子串词汇只是句子部分,则句子剩余部分还要继续去词库中查找
          if (r < sentence.length()) {
            queue.addFirst(sentence.substring(r));
          }

          break;
        }
      }

      // 没有在词库中找到对应子串词汇,则输出单个字母
      if (r == 0) {
        // 注意,这里只放一个字母到结果中,句子剩余部分继续去词库中查找
        ans.add(sentence.charAt(0) + "");

        if (sentence.length() > 1) {
          queue.addFirst(sentence.substring(1));
        }
      }
    }

    StringJoiner sj = new StringJoiner(",");
    ans.forEach(sj::add);

    return sj.toString();
  }
}
相关推荐
a努力。5 小时前
蚂蚁Java面试被问:流批一体架构的实现和状态管理
java·后端·websocket·spring·面试·职场和发展·架构
BLi4ee5 小时前
【Scholarly Notes】Adaptive Model Pruning for Federated Learning
算法·机器学习·剪枝
静听松涛1335 小时前
信息系统规划到上线全流程指南
论文阅读·面试·职场和发展·流程图
计算机学姐5 小时前
基于SpringBoot的在线骑行网站系统
java·vue.js·spring boot·后端·mysql·spring·tomcat
weixin_440730505 小时前
04python编程笔记-01基础知识+02三种结构
java·笔记·python
Remember_9935 小时前
【LeetCode精选算法】二分查找专题二
java·数据结构·算法·leetcode·哈希算法
空空kkk5 小时前
Java项目从单体到微服务的演变
java·运维·微服务
程农5 小时前
java计算机毕业设计婚纱摄影网站(附源码、数据库)
java·数据库·课程设计
BlockChain8885 小时前
Spring框架终极入门指南(12000字深度解析)
java·后端·python·spring