leetcode 面试题 17.13. 恢复空格【字典树】

题目

在这里插入图片描述

思路

动态规划+字典树
本题的主要思路其实是动态规划:

  1. 数组dp[i]的状态表示:前i个字符中,未识别的字符个数。
  2. 状态转移方程
  • 若存在j(j<=i),使得字符串sentence[j-1…i-1](下标从0开始)存在于dictionary中,则dp[i]=min(dp[i],dp[j-1]);
  • 否则,dp[i]=dp[i-1]+1;

此时,问题转化为,在dictionary中匹配字符串的问题,若一个一个暴力匹配,时间消耗太大,本题采用字典树来匹配。
字典树的优点:若某个前缀不是所有字符串的前缀,则可提前终止匹配。
字典树构建:本题因为要从i开始往前遍历(往0的方向),所以,按dictionary中字符串的倒序构建。

具体构建图示见官方题解:
(图源官方题解,侵删)
在这里插入图片描述

c++代码

class Trie {
public:
	Trie* next[26] = { NULL }; //26个字母
	bool is_end; //字符串结束标志
	Trie() { //构造函数
		is_end = false;
	}
	void insert(string s) {
		Trie* curpos = this;//初始根节点
		for (int i = s.size() - 1; i >= 0; --i) { //倒序构建
			int id = s[i] - 'a';
			if (curpos->next[id] == NULL)
				curpos->next[id] = new Trie();
			curpos = curpos->next[id];
		}
		curpos->is_end = true;//每个字符串的 尾节点设置字符串结束标志
	}
};
class Solution {
public:
	int respace(vector<string>& dictionary, string sentence) {
		int n = sentence.size();
		if (n == 0)return 0;
		Trie *root = new Trie();
		for (string dic : dictionary)
			root->insert(dic);
		vector<int>dp(n+1);
		for (int i = 1; i <= n; ++i) {
			dp[i] = dp[i - 1] + 1;
			Trie *cur = root;
			for (int j = i; j >= 1; --j) {
				int t = sentence[j-1] - 'a';
				if (cur->next[t] == NULL) //该后缀不存在
					break;
				else {
					if (cur->next[t]->is_end)
						dp[i] = min(dp[i], dp[j-1]);
					if (dp[i] == 0)break;//没有字符未识别,可直接跳出循环
				}
				cur = cur->next[t];
			}
		}
		return dp[n];
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值