难度困难468
给定一个 m x n
二维字符网格 board
和一个单词(字符串)列表 words
,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
示例 1:
输入:board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"] 输出:["eat","oath"]
示例 2:
输入:board = [["a","b"],["c","d"]], words = ["abcb"] 输出:[]
提示:
m == board.length
n == board[i].length
1 <= m, n <= 12
board[i][j]
是一个小写英文字母1 <= words.length <= 3 * 104
1 <= words[i].length <= 10
words[i]
由小写英文字母组成words
中的所有字符串互不相同
class Trie {
public:
Trie* next[26] = { nullptr }; //存储可能的下一个字符(小写字母共26位)
int isEnd;
Trie() { isEnd = -1; }
// 从头建立树
void insert(string s, int pos) {
Trie* cur = this;
for (int i = 0; i < s.length(); ++i) {
int t = s[i] - 'a';
if (cur->next[t] == nullptr) {
cur->next[t] = new Trie();
}
cur = cur->next[t];
}
cur->isEnd = pos;
}
};
class Solution {
public:
bool flag[13][13] = { 0 };
int dir_x[4] = { -1,0,0,1 };
int dir_y[4] = { 0,1,-1,0 };
int row, col;
string mid;
unordered_set<string>res;
void dfs(vector<vector<char>>& board, int x, int y, Trie *cur) {
if (cur->isEnd != -1)
res.insert(mid);
//cout << x << ' ' << y <<endl;
for (int i = 0; i < 4; i++)
{
int xx = x + dir_x[i];
int yy = y + dir_y[i];
if (xx >= 0 && xx < row && yy >= 0 && yy < col && flag[xx][yy] == 0) {
char s = board[xx][yy];
if (cur->next[s - 'a'] != nullptr) {
flag[xx][yy] = 1;
mid.push_back(s);
dfs(board, xx, yy, cur->next[s - 'a']);
flag[xx][yy] = 0;
mid.pop_back();
}
}
}
}
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
Trie *Start = new Trie();
row = board.size();
col = board[0].size();
for (auto s : words) {
Start->insert(s, 1);
}
for (int i = 0; i < board.size(); ++i) {
for (int j = 0; j < board[0].size(); ++j) {
char s = board[i][j];
if (Start->next[s - 'a'] != nullptr) {
flag[i][j] = 1;
mid.push_back(s);
dfs(board, i, j, Start->next[s - 'a']);
flag[i][j] = 0;
mid.pop_back();
}
}
}
vector<string>fin;
for (auto ss : res) {
fin.push_back(ss);
}
return fin;
}
};
难度中等169
哦,不!你不小心把一个长篇文章中的空格、标点都删掉了,并且大写也弄成了小写。像句子"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[] 用来记录结果。句子从前往后看,其中 dp[0]=0 表示句子是空字符串时没有未识别的字符,dp[i] 表示句子前 i 个字符中最少的未识别字符数。
对于前 i 个字符,即句子字符串的 [0,i),它可能是由最前面的 [0,j)子字符串加上一个字典匹配的单词得到,也就是 dp[i]=dp[j], j<i;也可能没找到字典中的单词,可以用它前 i-1 个字符的结果加上一个没有匹配到的第 i 个字符,即 dp[i]=dp[i-1]+1,每次更新最小的dp[i]。
为了更好的查找是否存在满足的字典,采用字典树结构优化,采用从末尾开始查找匹配到的字典,通过具体详解见:力扣
class Trie {
public:
Trie* next[26] = { nullptr }; //存储可能的下一个字符(小写字母共26位)
bool isEnd;
Trie() { isEnd = 0; }
// 从末尾建立树
void insert(string s) {
Trie* cur = this;
for (int i = s.length() - 1; i >= 0; --i) {
int t = s[i] - 'a';
if (cur->next[t] == nullptr) {
cur->next[t] = new Trie();
}
cur = cur->next[t];
}
cur->isEnd = 1;
}
};
class Solution {
public:
int respace(vector<string>& dictionary, string sentence) {
Trie* head = new Trie();
for (auto s : dictionary)
head->insert(s);
vector<int>dp(sentence.size() + 1,INT32_MAX);
dp[0] = 0;
for (int i = 1; i <dp.size(); ++i) {
Trie* cur = head;
dp[i] = dp[i - 1] + 1;
for (int j = i - 1; j >= 0; j--) {
int num = sentence[j] - 'a';
if (cur->next[num] == nullptr) {
break;
}
else if (cur->next[num]->isEnd) {
dp[i] = min(dp[i], dp[j]);
}
// if(dp[i] == 0)
// break;
cur = cur->next[num];
}
}
return dp[sentence.size()];
}
};
难度中等21
给定一个较长字符串big
和一个包含较短字符串的数组smalls
,设计一个方法,根据smalls
中的每一个较短字符串,对big
进行搜索。输出smalls
中的字符串在big
里出现的所有位置positions
,其中positions[i]
为smalls[i]
出现的所有位置。
示例:
输入: big = "mississippi" smalls = ["is","ppi","hi","sis","i","ssippi"] 输出: [[1,4],[8],[],[3],[1,4,7,10],[5]]
提示:
0 <= len(big) <= 1000
0 <= len(smalls[i]) <= 1000
smalls
的总字符数不会超过 100000。- 你可以认为
smalls
中没有重复字符串。 - 所有出现的字符均为英文小写字母。
class Trie {
public:
Trie* next[26] = { nullptr }; //存储可能的下一个字符(小写字母共26位)
int isEnd;
Trie() { isEnd = -1; }
// 从头建立树
void insert(string s, int pos) {
Trie* cur = this;
for (int i = 0; i < s.length(); ++i) {
int t = s[i] - 'a';
if (cur->next[t] == nullptr) {
cur->next[t] = new Trie();
}
cur = cur->next[t];
}
cur->isEnd = pos;
}
};
class Solution {
public:
vector<vector<int>> multiSearch(string big, vector<string>& smalls) {
vector<vector<int>>res(smalls.size());
if(big.size() == 0)
return res;
Trie* head = new Trie;
for (int i = 0; i < smalls.size(); ++i) {
head->insert(smalls[i], i);
}
cout << "sad" <<endl;
for (int i = 0; i < big.size(); ++i) {
Trie *cur = head;
for (int j = i; j < big.size(); ++j) {
int num = big[j] - 'a';
if (cur->next[num] == nullptr)
break;
else if (cur->next[num]->isEnd != -1)
res[cur->next[num]->isEnd].push_back(i);
cur = cur->next[num];
}
}
return res;
}
};