当允许重复子字符串时,查找给定字符串的第K个子字符串
Finding the K th lexicographically substring of a given string when the duplicate substrings are allowed
我想在允许重复子字符串的情况下找到给定字符串的字典顺序第k个最小子字符串。
假设给定字符串abc,则其子字符串按字典顺序依次为{a,ab,abc,b,c},现在假设给定K = 3,则ans为abc。
现在假设给定字符串aaa那么它的所有子字符串都是{a,a,a,aa,aaa,aa}所以现在如果K = 4,那么我们输出aa
然而,我在codeforces上遇到了以下代码,但我无法理解它。如有任何帮助,不胜感激。char s [MaxN];
bool b [MaxN];
int k, n;
void solve (vector <int> v)
{
int i, j;
int64 p, q;
char c;
vector <int> w;
for (c = 'a'; c <= 'z'; c++)
{
p = q = 0;
w.clear ();
for (j = 0; j < (int) v.size (); j++)
{
i = v[j];
if (s[i] == c)
{
w.push_back (i + 1);
p++;
q += n - i;
}
}
if (k < q)
break;
k -= q;
}
assert (c <= 'z');
putchar (c);
if (k < p)
return;
k -= p;
solve (w);
}
int main (void)
{
int i;
while (scanf (" %s %d", s, &k) != EOF)
{
n = (int) strlen (s);
if (k > ((((int64) n) * (int64) (n + 1)) >> 1LL))
{
printf ("No such line.n");
continue;
}
k--;
vector <int> v;
for (i = 0; i < n; i++)
v.push_back (i);
solve (v);
putchar ('n');
}
return 0;
}
这里是问题的链接http://codeforces.com/problemset/problem/128/B
Shubajit Saha使用后缀数组的方法是不正确的。考虑字符串abaab
,其排序后的后缀为(基于0):
2. aab
3. ab
0. abaab
4. b
1. baab
根据他的说法,从后缀2. aab
得到的子串aab
小于从3. ab
得到的子串a
,这显然是错误的!
正确的方法是使用后缀自动机+动态规划。你可以在CP-Algorithm了解它。这是一个写得很好的关于后缀自动机的教程。
按字典顺序排列的第k个子字符串对应后缀自动机中按字典顺序排列的第k个路径。因此,在计算了每个状态的路径数之后,我们可以很容易地从自动机的根开始搜索第k条路径。注意,这个问题允许重复的子字符串,所以不应该用1初始化每个状态,而应该用在该状态结束的子字符串的数量初始化。要做到这一点,请参考教程中的Number of occurrences
节。
这种方法的一个优点是时间复杂度不取决于k,它只取决于子字符串的长度(最多为n),因此,k可以比问题中的约束大得多(1e10就可以了)。
下面是我的c++代码:https://codeforces.com/contest/128/submission/72601519
时间复杂度为O(nlgn)
。虽然构建后缀自动机并遍历它是O(n)
,但我们需要根据状态的长度对它们进行排序。我使用STD排序,这是O(nlgn)
。您可以使用计数排序来使其线性化。
解决这个问题的标准方法是构造给定字符串的后缀数组。后缀数组以字典顺序排序的方式为我们提供给定字符串的所有后缀。一旦我们有了给定字符串的所有排序后缀,观察字符串的每个子字符串都是某个后缀的前缀。如果我们按照字典序升序遍历每个大小为l的后缀,就会得到l个子字符串,每个子字符串都小于从字典序上比我们考虑的后缀大的后缀得到的子字符串。因此,我们可以很容易地找到第k个最小的子字符串,通过填充子字符串的计数。
实际上,后缀数组是用来解决这个问题的一个更困难的版本,你有Q个查询,找到第K个子字符串,其中K在每个查询中是不同的。
关于你的问题中的代码,因为你必须找到第k个子字符串只有一次,解决方案的方法本质上使用相同的逻辑,但不同的实现。
- 如果用户输入无效,如何使用字符串变量-C++重复输入命令
- 有哪些有效的方法可以消除一组 100 万个字符串>重复数据?
- 使用 char 分隔符解析C++中的字符串,但将可重复的字符保留为每个解析的子字符串 (C++ STL) 中的分隔符
- C++ - 链表字符串重复
- 如何在 c++ 中使用字符串重复?
- 如何检查字符串中是否有重复的负号?例如 --1
- 给定一个字符串数组,如何删除重复项?
- 删除字符串向量中的字符重复
- 字符串重复替换为连字符 C++
- 打印可以重复以获取原始字符串的最小字符串
- 如何在 C++03 中没有重复代码的情况下在堆栈上创建一个非常量 C 字符串数组?
- 在C 语言中与字符串重复的混淆
- 查找单个字符串中重复次数最多和次数第二多的字符
- 打印频率和重复的字符串
- 在字符串矢量中删除前2个字符的重复
- 解析字符串导致重复的值
- 理解删除字符串中重复字符的代码(来自破解编码面试)
- 字符串流重复最后一个单词
- 检查字符串是否重复特定字符
- 如何使用新的c++0x正则表达式对象在字符串中重复匹配