牛牛现在有两个字符串s和t,这两个字符串只包含小写字母。
牛妹有一个空字符串z,牛妹每次可以从牛牛那里取s字符串的任意一个子序列加到z字符串的后面。牛妹可以一直从s字符串中取出子序列(取过的子序列也可以再取),而不会对s字符串造成任何影响。
现在牛妹问牛牛,最少要取多少次才能让z字符串与t字符串相等?
牛牛不知道该如何解答,他想请你帮他写一个程序,返回使z字符串与t字符串相等牛妹最少需要取的次数,如果牛妹不可能完成,请返回-1。
时间复杂度: 空间复杂度:
解题思路:
为了解题方便,我们首先可以使用vector存s中26个字母的下标位置,然后在t中遍历查找,用p记录查到上一个字符在字符串s中的位置。
如果在t内有一个字符没有在s中,那就说明牛妹无法构造成功,返回-1;
如果当前的p大于等于这个字符在s中出现的最后一个位置,说明这一次子序列已经到头了,不能往后继续遍历了,这时我们需要重新开始一次从头取子序列,让ans++,更新p,让p等于当前字符在s中出现的第一个位置;如果不是,我们可以使用二分查找(二分查找有很多方法,可以手写一个,我这里为了方便用了c++库里自带的),查找大于p出现的第一个该字符的位置,使p等于这个位置。
将以上思想,用代码实现,如下:
inline int gid(char s)
{
return s - 'a';
}
/**
* 返回使z字符串与t字符串相等牛妹最少需要取多少次,如果牛妹不可能完成,请返回-1
* @param s string字符串 代表字符串s
* @param t string字符串 代表字符串t
* @return int整型
*/
int solve(string s, string t)
{
// write code here
vector<int> v[26];
int siz[26];
memset(siz, 0, sizeof siz);
int lens = s.size(), lent = t.size(), i, j, d, p = -1, pd, ans = 1;
for (i = 0; i < 26; i++)
v[i].clear();
for (i = 0; i < lens; i++)
{
d = gid(s[i]);
v[d].push_back(i);
siz[d]++;
}
for (i = 0; i < lent; i++)
{
d = gid(t[i]);
if (siz[d] == 0)
return -1;
if (p >= v[d][siz[d] - 1])
{
ans++;
p = v[d][0];
}
else
{
pd = upper_bound(v[d].begin(), v[d].end(), p) - v[d].begin();
p = v[d][pd];
}
}
return ans;
}
京公网安备 11010502036488号