[CareerCup] 17.14 Unconcatenate Words 断词

简介:

17.14 Oh, no! You have just completed a lengthy document when you have an unfortunate Find/Replace mishap. You have accidentally removed all spaces, punctuation, and capitalization in the document. A sentence like "I reset the computer. It still didn't boot!" would become "iresetthecomputeritstilldidntboot". You figure that you can add back in the punctation and capitalization later, once you get the individual words properly separated. Most of the words will be in a dictionary, but some strings, like proper names, will not.

Given a dictionary (a list of words), design an algorithm to find the optimal way of "unconcatenating" a sequence of words. In this case, "optimal" is defined to be the parsing which minimizes the number of unrecognized sequences of characters.

For example, the string "jesslookedjustliketimherbrother" would be optimally parsed as "JESS looked just like TIM her brother". This parsing has seven unrecognized characters, which we have capitalized for clarity.

我们需要拆分字符串,LeetCode中有类似的题目Word Break IIWord Break,但是又有不同,这道题允许有无法拆分的单词,那么对于这种问题,我们的目的是使无效的字母越少越好,基本的解法见parseSimple()函数,该函数可以有两点优化:

1. 一些递归重复计算了,我们可以使用哈希表来保存之前计算好的最优拆分了,那么在之后的递归中遇到了直接取出来用就行了。

2. 在有些情况下我们可以预测一种拆分方式是否会生成无效单词,比如当我们拆分单词xten,没有单词是以xt开头的,但是当前的算法会计算xt+p(en),xten+p(n)和xten。每一次我们都会发现这样的单词不存在,这样我们直接在x后面加一个空格就可以了,那么我们怎么样知道没有单词是以xt开始的呢,用前缀树trie,参见parseOptimized()函数。

我们使用哈希表来缓存结果,关键字是单词的起始位置,我们保存了最佳的位置来拆分余下的字符串。我们可以让代码返回拆分好的字符串,但是比较麻烦。我们使用一个外包类Result来返回无效字符的个数和最优字符串,而在C++中就不用这样,因为可以通过引用传递。

import java.util.Hashtable;
import CtCILibrary.AssortedMethods;
import CtCILibrary.Trie;

public class j {
    public static String sentence;
    public static Trie dictionary;
    
    public static Result parse(int start, int end, Hashtable<Integer, Result> cache) {
        if (end >= sentence.length()) {
            return new Result(end - start, sentence.substring(start).toUpperCase());
        }
        if (cache.containsKey(start)) {
            return cache.get(start).clone();
        }
        String curWord = sentence.substring(start, end + 1);
        boolean validPartial = dictionary.contains(curWord, false);
        boolean validExact = validPartial && dictionary.contains(curWord, true);
        
        Result bestExact = parse(end + 1, end + 1, cache);
        if (validExact) {
            bestExact.parsed = curWord + " " + bestExact.parsed;
        } else {
            bestExact.invalid += curWord.length();
            bestExact.parsed = curWord.toUpperCase() + " " + bestExact.parsed;
        }
        
        Result bestExtend = null;
        if (validPartial) {
            bestExtend = parse(start, end + 1, cache);
        }
        
        Result best = Result.min(bestExact, bestExtend);
        cache.put(start, best.clone());
        return best;
    }
    
    public static int parseOptimized(int start, int end, Hashtable<Integer, Integer> cache) {
        if (end >= sentence.length()) {
            return end - start;
        }
        if (cache.containsKey(start)) {
            return cache.get(start);
        }
        String curWord = sentence.substring(start, end + 1);
        boolean validPartial = dictionary.contains(curWord, false);
        int bestExact = parseOptimized(end + 1, end + 1, cache);
        if (!validPartial || !dictionary.contains(curWord, true)) {
            bestExact += curWord.length();
        }
        int bestExtend = Integer.MAX_VALUE;
        if (validPartial) {
            bestExtend = parseOptimized(start, end + 1, cache);
        }
        int min = Math.min(bestExact, bestExtend);
        cache.put(start, min);
        return min;
    }
    
    public static int parseSimple(int start, int end) {
        if (end >= sentence.length()) {
            return end - start;
        }
        String word = sentence.substring(start, end + 1);
        int bestExact = parseSimple(end + 1, end + 1);
        if (!dictionary.contains(word, true)) {
            bestExact += word.length();
        }
        int bestExtend = parseSimple(start, end + 1);
        return Math.min(bestExact, bestExtend);
    }
    
    public static String clean(String str) {
        char[] punctuation = {',', '"', '!', '.', '\'', '?', ','};
        for (char c : punctuation) {
            str = str.replace(c, ' ');
        }
        return str.replace(" ", "").toLowerCase();
    }
    
    public static void main(String[] args) {
        dictionary = AssortedMethods.getTrieDictionary();
        sentence = "As one of the top companies in the world, Google will surely attract the attention of computer gurus. This does not, however, mean the company is for everyone.";
        sentence = clean(sentence);
        System.out.println(sentence);
        // parse
        Result res = parse(0, 0, new Hashtable<Integer, Result>());
        System.out.println(res.parsed);
        System.out.println(res.invalid);
        System.out.println();
        // optimized parse
        int v = parseOptimized(0, 0, new Hashtable<Integer, Integer>());
        System.out.println(v);
    }
}

public class Result {
    public int invalid = Integer.MAX_VALUE;
    public String parsed = "";
    public Result(int inv, String p) {
        invalid = inv;
        parsed = p;
    }
    
    public Result clone() {
        return new Result(this.invalid, this.parsed);
    }
    
    public static Result min(Result r1, Result r2) {
        if (r1 == null) {
            return r2;
        } else if (r2 == null) {
            return r1;
        }
        return r2.invalid < r1.invalid ? r2 : r1;
    }
}

本文转自博客园Grandyang的博客,原文链接:断词[CareerCup] 17.14 Unconcatenate Words ,如需转载请自行联系原博主。

相关文章
|
人工智能 自然语言处理 安全
探秘SuperCLUE-Safety:为中文大模型打造的多轮对抗安全新框架
探秘SuperCLUE-Safety:为中文大模型打造的多轮对抗安全新框架【2月更文挑战第2天】
探秘SuperCLUE-Safety:为中文大模型打造的多轮对抗安全新框架
|
消息中间件 存储 负载均衡
深入了解Kafka中Topic的神奇之处
深入了解Kafka中Topic的神奇之处
828 0
|
数据可视化 安全 数据安全/隐私保护
使用Python做个可视化的“剪刀石头布”小游戏
使用Python做个可视化的“剪刀石头布”小游戏
427 0
|
存储 云计算 对象存储
云计算——ACA学习 云计算分类
云计算——ACA学习 云计算分类
410 0
|
编译器 C# Windows
Inno Setup制作安装包教程
Inno Setup制作安装包教程
1642 0
|
7月前
|
传感器 人工智能 供应链
一场关于物料清单BOM的深度对话
这段对话发生在某科技公司茶水间,新入职的采购专员张薇向供应链总监陈峰请教BOM表的作用。陈峰以乐高说明书为喻,解释BOM是产品的物料清单,涵盖零件型号、用量与供应商信息。他通过实例说明BOM错误可能引发采购、生产和售后等环节的连锁问题,如材料浪费、返工增加及客户索赔。最后,陈峰提出通过源头管控、动态监测和反向追溯优化BOM管理,并强调其准确率对提升企业毛利率的重要性,展现了BOM在现代制造业中“悄然重写利润法则”的核心地位。
200 12
|
存储 弹性计算 监控
阿里云ECS健康状态产品详解
详细介绍阿里云ECS健康状态的功能和使用案例
|
Linux
CentOS-Stream-9配置chfs
通过上述步骤,您就可以在CentOS Stream 9上配置并运行CHFS,为用户提供基于HTTP的文件分享服务。请注意,实际操作时应根据CHFS的具体版本和文档进行适当调整。
459 0
|
大数据 关系型数据库 数据库
python 批量处理大数据写入数据库
python 批量处理大数据写入数据库
761 0
NSS [SWPUCTF 2021 新生赛]pop
NSS [SWPUCTF 2021 新生赛]pop
211 0