文章目录
- 字符串模式匹配
- 移除子串
- n个人排名,允许并列名次,共有多少种排名结果?
- 三个线程交替打印ali
- 扔鸡蛋
- 输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变
- 把数组排成最小的数
- 计算 n!阶乘的结果的末尾有几个0
- 1堆n个石子每次最多取m个
- 一个字符串中连续出现次数最多的子串
- 给定一个无序整型数组,找出数组中未出现的最小正整数
- 圆圈中剩下的最后一个数
- 序列变为0
- 给定两个字符串s和t,判断s是否是t的子序列
- 最小覆盖子串
- 猴子分桃
- 缺少的最小正数
- 无重复字符的最长子串
- 旋转数组的最小值
- 字符串转整数(atoi)
- 用栈实现队列
- 用队列实现栈
- 汽车加油站问题
- K个一组翻转链表
- 删除驼峰式字符串
字符串模式匹配
问题描述:
有一个字符串它的构成是词+空格的组合,如“北京 杭州 杭州 北京”, 要求输入一个匹配模式(简单的以字符来写), 比如 a a b b aabb aabb, 来判断该字符串是否符合该模式。
举例:
1. pattern = "abba", str="北京 杭州 杭州 北京" 返回 true
2. pattern = "aabb", str="北京 杭州 杭州 北京" 返回 false
3. pattern = "baab", str="北京 杭州 杭州 北京" 返回 true
解题思路:
-
对于 p a t t e r n pattern pattern,我们需要将其每一个字符都需要对应 s t r str str 中的一个词。
-
从左到右同时遍历字符数组和单词数组,并在该过程中:
-
当 p a t t e r n pattern pattern 字符数组第一次出现某一字符时,根据其在单词数组中的位置,记录该字符对应的单词;
-
当 p a t t e r n pattern pattern 字符数组第 N N N 次( N > 1 N > 1 N>1 )出现某一字符时,取出该字符应该对应的单词,并与当前字符对应在单词数组中的单词对比,如果相同则继续校验,否则返回 f a l s e false false。
-
如果校验至最后一个单词仍然成立,则返回 t r u e true true。
问题:如何知道字符是不是第一次出现呢? 如何记录某一字符所对应的单词呢?
- 通过 u n o r d e r e d _ m a p unordered\_map unordered_map将字符和单词进行映射
- 通过 f i n d find find函数可判断该字符(键)是否存在
- 如果不存在则表示是第一次出现,我们需要建立字符和单词之间的映射关系
- 否则,如果该字符已经存在,则需要和当前遍历到的单词与该字符已经建立映射关系的单词进行比较。
- 如果两者不相等,返回 f a l s e false false
- 否则,继续进行下一个单词的遍历
- 直到当所有的单词比较完成,返回 t r u e true true
代码实现:
字符串分割的函数
vector<string> split(const string &str, const string &pattern)
{
vector<string> res;
size_t start = 0, index = str.find_first_of(pattern, 0);
while (index != str.npos)
{
if (start != index)
{
res.push_back(str.substr(start, index - start));
}
start = index + 1;
index = str.find_first_of(pattern, start);
}
if (!str.substr(start).empty())
{
res.push_back(str.substr(start));
}
return res;
}
字符串匹配的函数
bool matchPattern(const string &str, const string &pattern)
{
//首先将str进行拆分
vector<string> words = split(str, " ");
//判断分割完成之后的单词长度是否等于模式的长度
if (words.size() != pattern.length())
{
return false;
}
//建立单词和拆分的单词之间的映射关系
unordered_map<char, string> map;
//从左到右同时遍历字符数组和单词数组
for (int i = 0; i < pattern.length(); ++i)
{
//如果字符是第一次出现则建立映射关系
if (map.find(pattern[i]) == map.end())
{
map.insert(make_pair(pattern[i], words[i]));
}
// 否则直接进行比较
else
{
if (map[pattern[i]] != words[i])
{
return false;
}
}
}
return true;
}
移除子串
问题描述:
给定一个字符串以及多个子串,对于在字符串中出现的子串可以多次移除,求多次移除后能够得到的最短字符串长度。
输入: 第一行为一个字符串,第二行为多个子串,字符串长度大于0
输出: 多次移除后能够得到的最短字符串长度
示例1:
输入:
"ccdaabcdbb"
["ab","cd"]
输出:
2
解释:
ccdaabcdbb -> ccdacdbb -> cabb -> cb (length = 2)
示例 2:
输入:
"abcabd"
["ab","abcd"]
输出:
0
解释:
abcabd -> abcd -> "" (length = 0)
————————
解题思路:
- 每次取队列首元素作为要处理的主串
- 在主串中找到每个子串(该子串有可能重复出现在主串中),将剔除子串之后的主串添加进set集合和queue队列中,并更新剔除子串之后主串的长度
- 当队列为空时,表示所有的情况都处理完毕,返回最小的长度
代码实现:
int moveSubstr(string &s, unordered_set<string> &dict)
{
int size = s.size();
if (size == 0)
{
return 0;
}
queue<string> q;//存放待处理的主串
unordered_set<string> hashSet;//记录每种可能存在的主串的情况
int minLen = size;//最小的长度
q.push(s);//首先把原始主串添加进去
hashSet.insert(s);
while (!q.empty())
{
string s = q.front();//每次取队头元素作为待处理的主串
q.pop();//从队列中删除,表示该主串将要被处理
//遍历每个子串
for (auto it = dict.begin(); it != dict.end(); it++)
{
string str = *it;
//在主串中找子串,返回子串中第一个字符出现的位置
int pos = s.find(str);
while (pos != s.npos)//找到了
{
//new_s表示剔除子串之后的主串
string new_s = s.substr(0, pos) + s.substr(pos + str.size());
//没有在hashSet中找到,表示该字符串没有被处理过
if (hashSet.find(new_s) == hashSet.end())
{
q.push(new_s);//加入待处理队列
hashSet.insert(new_s);//加入hashSet中,算是一种优化
minLen = min(minLen, (int)new_s.size());//更新最小长度
// 因为可能存在同一个子串在主串中多次出现,我们必须处理该子串在主串中不同位置的情况
pos = s.find(str, pos + 1);
}
}
}
return minLen;
}
n个人排名,允许并列名次,共有多少种排名结果?
解题思路
- d p [ i ] [ j ] dp[i][j] dp[i][j]:表示 i i i个人,名次个数为 j j j时,有多少种排名方法
- j = = 1 j==1 j==1,表示 i i i个人,全部都是并列排名
i > = j i>=j i>=j,表示有并列排名,也有独占一个名次的 - 如果 i − 1 i-1 i−1个人有 j j j个名次,那么如果第 i i i个人和前边的 i − 1 i-1 i−1个人