(34)面试题 17.13. 恢复空格(e)

题目链接:
https://leetcode-cn.com/problems/re-space-lcci/
难度:中等
面试题 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中只包含小写字母。

我笑了 这算中等难度??? 好TM难 只能选择看解析。。。
思路一 Trie + 动态规划
今天 又接触到一个新的东西 字典树Trie 典型的空间换时间
动态规划dp[i] 表示前i个字符最少的未识别的字符数量,从前往后计算。动态转化方程

找到了:dp[i]=min(dp[i],dp[j-1]) 
	解释: j->i 组成的字符串 即sentence[j-1... i-1]
未找到:dp[i]=dp[i-1]+1

tree 字典树 倒叙插入

// 字典树
class Trie {
public:
    Trie* next[26] = {nullptr};
    // 标识
    bool isEnd;
    
    Trie() {
        isEnd = false;
    }

    void insert(string s) {
        Trie* curPos = this;
		// 下标共26 分别代表各个字母
        for (int i = s.length() - 1; i >= 0; --i) {
            int t = s[i] - 'a';
            // 若为空 初始化
            if (curPos->next[t] == nullptr) {
                curPos->next[t] = new Trie();
            }
            // 非空 则表示所对应的字母存在
            // 更新curPos 对字符串当前状态更新
            curPos = curPos->next[t];
        }
        // 到此处是否为一个单词
        curPos->isEnd = true;
    }
};

class Solution {
public:
    int respace(vector<string>& dictionary, string sentence) {
    	// inf为无穷大数 (可以认为)。。。 
    	// 据说这样设置有好处
    	// 无穷大加一个有穷的数依然是无穷大
    	// 无穷大加无穷大还是无穷大
        int n = sentence.length(), inf = 0x3f3f3f3f;
		
		// 初始化字典树 trie
        Trie* root = new Trie();
        for (auto& word: dictionary) {
            root->insert(word);
        }
        // 初始化dp
        vector<int> dp(n + 1, inf);
        dp[0] = 0;
        for (int i = 1; i <= n; ++i) {
        	// 假设未找到
            dp[i] = dp[i - 1] + 1;

            Trie* curPos = root;
            // 开始寻找
            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) {
                // 查找成功 i到j为一个单词
                    dp[i] = min(dp[i], dp[j - 1]);
                }
                // dp[i]==0 那还查个毛线 推出呗
                if (dp[i] == 0) {
                    break;
                }
                // 更新curPos继续查找
                curPos = curPos->next[t];
            }
        }
        return dp[n];
    }
};

官方题解还有一种方法 个人感觉还是动态规划的思路 只不过查找方式变了 将字符串转换为整数类型进行查找 不过没研究透彻 过几天再说。。。。

你可能感兴趣的:(菜鸟的算法学习,leetcode)