【程序员面试金典】面试题 17.13. 恢复空格

这篇具有很好参考价值的文章主要介绍了【程序员面试金典】面试题 17.13. 恢复空格。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目描述

描述:哦,不!你不小心把一个长篇文章中的空格、标点都删掉了,并且大写也弄成了小写。像句子"I reset the computer. It still didn’t boot!“已经变成了"iresetthecomputeritstilldidntboot”。在处理标点符号和大小写之前,你得先把它断成词语。当然了,你有一本厚厚的词典dictionary,不过,有些词没在词典里。假设文章用sentence表示,设计一个算法,把文章断开,要求未识别的字符最少,返回未识别的字符数。

注意:本题相对原题稍作改动,只需返回未识别的字符数

示例:

输入:
dictionary = ["looked","just","like","her","brother"]
sentence = "jesslookedjustliketimherbrother"
输出: 7
解释: 断句后为"jess looked just like tim her brother",共7个未识别字符。

提示:

0 <= len(sentence) <= 1000
dictionary中总字符数不超过 150000。
你可以认为dictionary和sentence中只包含小写字母。

解题思路

思路:最直观的想法是,动态规划+字典树。使用dp[i]表示长度为i的字符串的最少未识别字符,如果下标0i-1(长度1i)之间未匹配,则dp[i]=dp[i-1]+1,反之如果下标j-1i-1(长度ji)之间发生匹配,则dp[i]=dp[j-1]+1,其中字典树需要逆序构建喔!

class Trie {
public:
	//下一个字母
    Trie* next[26];
    //该字符是否是该单词的结束位置
    bool isEnd;
    //前缀树类的构造函数
    Trie(){
        isEnd=false;
        memset(next,0,sizeof(next));
    }
    //向字典树中插入单词(可根据需求选择正序或者逆序插入)
    void insert(string s)
    {
        //逆序插入
        Trie* curPos=this;
        for(int i=s.size()-1;i>=0;i--)
        {
            int t=s[i]-'a';
            if(curPos->next[t]==nullptr)
                curPos->next[t]=new Trie();
            curPos=curPos->next[t];
        }
        curPos->isEnd=true;
    }
};
class Solution {
public:
    int respace(vector<string>& dictionary, string sentence) {
        int n=sentence.size();
        int m=dictionary.size();
        //创建字典树对象 使用指针root指向该对象
        Trie* root=new Trie();
        //构建字典树
        for(auto dic:dictionary)
        {
            root->insert(dic);
        }
        //dp[i]表示以长度为i结尾的最少未识别字符
        vector<int> dp(n+1,INT_MAX);
        //长度为0的字符串未识别的为0
        dp[0]=0;
        //i表示第几个字符
        for(int i=1;i<=n;i++)
        {
            dp[i]=dp[i-1]+1;
            Trie* curPos=root;
            //j表示第几个字符
            for(int j=i;j>=1;j--)
            {
                //字符对应的下标
                int t=sentence[j-1]-'a';
                //如果当前字符在字典树中不存在则直接退出
                if(curPos->next[t]==nullptr)
                    break;
                //如果当前字符在字典树中且已经结束则求取最小长度
                else if(curPos->next[t]->isEnd) 
                    dp[i]=min(dp[i],dp[j-1]);
                curPos=curPos->next[t];
            }
        }
        return dp[n];
    }
};

总结:注意字典树的数据结构编写方式!!!root->insert!!!

字典树介绍

  1. 实现 Trie (前缀树)

前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。

请你实现 Trie 类:

Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

示例:

输入
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]

解释
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // 返回 True
trie.search("app");     // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app");     // 返回 True

提示:

1 <= word.length, prefix.length <= 2000
word 和 prefix 仅由小写英文字母组成
insert、search 和 startsWith 调用次数 总计 不超过 3 * 104 次

思路:最直观的想法是,字典树。字典树,一次建树,多次查询。

class Trie {
private:
    bool isEnd; //标记是否为单词结尾
    Trie* next[26]; //标记下一个节点可能是什么 分别是a,b,c,d...
public:
    Trie() {
        isEnd=false;
        memset(next,0,sizeof(next));
    }
    void insert(string word) {
        //首先指向当前这棵树
        Trie* node=this;
        //遍历单词
        for(char c:word)
        {
            //如果对应为空则新建
            if(node->next[c-'a']==NULL)
                node->next[c-'a']=new Trie();
            //然后将节点指向当前(为下一次准备)
            node=node->next[c-'a'];
        }
        //置单词结束标志
        node->isEnd=true;
    }
    bool search(string word) {
        //首先指向当前这棵树
        Trie* node=this;
        for(char c:word)
        {
            node=node->next[c-'a'];
            if(node==NULL)
                return false;
        }
        return node->isEnd;
    }
    bool startsWith(string prefix) {
        //首先指向当前这棵树
        Trie* node=this;
        for(char c:prefix)
        {
            node=node->next[c-'a'];
            if(node==NULL)
                return false;
        }
        return true;
    }
};

总结:字典树一般用于单词查找和前缀匹配。文章来源地址https://www.toymoban.com/news/detail-500508.html

到了这里,关于【程序员面试金典】面试题 17.13. 恢复空格的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【程序员面试金典】面试题 17.25 . 单词矩阵

    描述:给定一份单词的清单,设计一个算法,创建由字母组成的面积最大的矩形,其中每一行组成一个单词(自左向右),每一列也组成一个单词(自上而下)。不要求这些单词在清单里连续出现,但要求所有行等长,所有列等高。 如果有多个面积最大的矩形,输出任意一个均可

    2024年02月12日
    浏览(10)
  • 【程序员面试金典】面试题 17.19. 消失的两个数字

    描述:给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗? 以任意顺序返回这两个数字均可。 示例 1: 示例 2: 提示: nums.length = 30000 思路:最直观的想法是,位运算。消失的两个数字和只出现一次的两个元素,本质

    2024年02月12日
    浏览(15)
  • 【程序员面试金典】面试题 17.14. 最小K个数

    描述:设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。 示例: 提示: 0 = len(arr) = 100000 0 = k = min(100000, len(arr)) 思路:最直观的想法是,排序。 扩展:最大堆。最小的k个数,那么就可以维持一个大小为k的最大堆,先填充k个数到最大堆中,然后再依次遍

    2024年02月11日
    浏览(9)
  • 【程序员面试金典】面试题 17.21. 直方图的水量

    【程序员面试金典】面试题 17.21. 直方图的水量

    描述:给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图能存多少水量?直方图的宽度为 1。 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的直方图,在这种情况下,可以接 6 个单位的水(蓝色部分表示水)。 感谢 Marcos 贡献此图。 示例: 思路:最直观的想

    2024年02月11日
    浏览(10)
  • 《程序员面试金典(第6版)面试题 16.10. 生存人数(前缀和思想)

    《程序员面试金典(第6版)面试题 16.10. 生存人数(前缀和思想)

    给定 N 个人的出生年份和死亡年份,第 i 个人的出生年份为 birth[i],死亡年份为 death[i],实现一个方法以计算生存人数最多的年份。 你可以假设所有人都出生于 1900 年至 2000 年(含 1900 和 2000 )之间。如果一个人在某一年的任意时期处于生存状态,那么他应该被纳入那一年的

    2024年02月02日
    浏览(11)
  • 《程序员面试金典(第6版)》 面试题 08.11. 硬币(动态规划,组合问题,C++)

    《程序员面试金典(第6版)》 面试题 08.11. 硬币(动态规划,组合问题,C++)

    硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007) 示例1: 输入: n = 5 输出:2 解释: 有两种方式可以凑成总金额: 5=5 5=1+1+1+1+1 示例2: 输入: n = 10 输出:4 解释: 有四种方式可以凑成总金额: 1

    2023年04月08日
    浏览(11)
  • 13个程序员常用开发工具用途推荐整理

    作为一名刚入门的程序员,选择合适的开发工具可以提高工作效率,加快学习进度。在本文中,我将向您推荐10个常用的开发工具,并通过简单的例子和代码来介绍它们的主要用途。 Visual Studio Code(VSCode)是一个免费、开源且跨平台的代码编辑器,支持多种编程语言。它具有

    2024年02月07日
    浏览(33)
  • 读程序员的制胜技笔记13_安全审查(上)

    读程序员的制胜技笔记13_安全审查(上)

    5.6.1.1. 任何你不想丢失或泄露的东西都是资产,包括你的源代码、设计文档、数据库、私钥、API令牌、服务器配置,还有Netflix观看清单 5.6.2.1. 每台服务器都会被一些人访问,而每台服务器都会访问其他一些服务器 6.1.1.1. 设计时首先要考虑到安全问题,因为在既有基础上去

    2024年02月05日
    浏览(12)
  • 读程序员的README笔记13_技术设计流程(上)

    读程序员的README笔记13_技术设计流程(上)

    3.4.1.1. 外界干扰是深度工作的“杀手” 3.4.1.2. 避免所有的交流方式 3.4.1.2.1. 关闭聊天 3.4.1.2.2. 关闭电子邮件 3.4.1.2.3. 禁用电话通知 3.4.1.2.4. 换个地方坐 3.4.2.1. 有形产出是一份设计文档 4.2.3.1. 如果有一个以上的问题,询问哪些问题是最优先的 4.3.7.1. 注意与外人交流时不

    2024年02月04日
    浏览(31)
  • 读程序员的README笔记17_构建可演进的架构(下)

    读程序员的README笔记17_构建可演进的架构(下)

    1.3.3.1. 开发人员可以只专注于和自己相关的字段,因为它们会继承其他字段的默认值 1.3.3.2. 默认值可使大型API在感觉上很小巧 1.4.1.1. OpenAPI通常用于RESTful服务 1.4.1.2. non-REST服务则使用Protocol Buffers、Thrift或类似的接口定义语言(interface definition language,IDL) 1.4.1.3. 接口定义工

    2024年02月04日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包