【问题标题】:How to count the number of ways of choosing of k equal substrings from a List L(the list of All Substrings)如何计算从列表 L(所有子字符串的列表)中选择 k 个相等子字符串的方式的数量
【发布时间】:2015-08-23 01:04:55
【问题描述】:

给定一个由N 小写英文字母组成的字符串S

假设我们有一个列表L,由字符串S的所有非空子字符串组成。

我需要计算从列表L 中精确选择K 相等字符串的方法的数量(请注意,子字符串的长度不必等于k)。 1≤N≤5000 1≤K≤10^9

例子:

Let S=ababa. 

As List L = {"a", "b", "a", "b", "a", "ab", "ba", "ab", "ba", "aba", "bab", "aba", "abab", "baba", "ababa"}

let k=2

路数为7:

("a", "a")
("a", "a") 
("a", "a") 
("b", "b") 
("ab", "ab") 
("ba", "ba") 
("aba", "aba")

同样:

let k=3

方法的数量将是 1:

("a", "a", "a")

【问题讨论】:

    标签: algorithm


    【解决方案1】:

    “所有子字符串的列表”。为什么会有所有子字符串的列表?假设您有一百万个字符的字符串,有 5000 亿个子字符串。根本不需要所有子字符串的列表来解决问题。

    如果 K = 0,那么有一种方法。 如果 K = 1,则有 N 种方式。

    对于 k = 1 到 N,每个长度为 k 的子串可以从 0 到 N - k 的索引开始,即 N - k + 1 个子串。识别不同的字符串并使用哈希表计算每个字符串的数量。然后对于每个出现 n 次的不同字符串,n >= k,将 (n over K) 添加到您的计数中。

    就是这样。

    您可以通过首先查看长度为 1 的字符串来更快地做到这一点,忽略所有少于 K 个相等字符串的字符串,计算方式的数量,然后在每个字符串中添加另一个字符并重复。假设 K = 5,字符串中有 100 万个字符,并且只有两个长度为 6 的子字符串出现了 5 次或更多次,那么您只需在这两个子字符串中添加字符即可。

    【讨论】:

    • 如果k=1,则路数就是子串的个数,即O(n^2)。但我认为这是正确的做法。
    • 我不明白你写的内容
    【解决方案2】:

    没有任何关于你正在学习的语言的细节,我相信你可以通过一个简单的嵌套循环来完成这个。只需将每个值与数组或列表中的所有值进行比较即可。

    【讨论】:

    • 这真的很模糊,也不是很有帮助。你能详细说明一下吗?
    【解决方案3】:

    为给定的字符串构建suffix array

    遍历这个数组,寻找(至少 k 个)相邻后缀的共同起始符号。

    【讨论】:

    • 能否提供c中后缀数组的链接
    • 试试google,不知道哪个C实现简单好用。任意一个:codeforces.com/blog/entry/4025,带有有用的 LCP
    【解决方案4】:

    以下是 JavaScript 中的内容:

    function choose(n,k){
     if(k>n)return 0;if(k==0||n==k)return 1;var p=n;for(var i=2;i<=k;i++)p*=(n+1-i)/i;return p;
    }
    
    function f(str,k){
      var n = str.length,
          h = {},
          count = 0;
    
      for (var i=0; i<n; i++){
        var s = "";
        for (var j=i; k <= n - j + i && j < n; j++){
          s += str.charAt(j);
          if (h[s])
            h[s]++;
          else
            h[s] = 1;
        }
      }
    
      for (var i in h)
        count += choose(h[i],k);
    
      return count;
    }
    

    输出:

    console.log(f("ababa",2));
    console.log(f("ababa",3));
    
    7
    1
    

    【讨论】:

    • 这真的很难阅读:1 个字母的变量名称,一个高尔夫脚本选择函数,省略可选的 {},并且没有 cmets。请做得更好。
    • @Teepeemm 感谢您的评论。请帮助我理解您所说的“更好”是什么意思,因为我有时取决于我的心情。这一次,当我看到你的评论时,我的直觉是将“更好”定义为提供线索,但仍然给那些还不完全清楚的人留下一些思考。不过,为了逐点解决您的评论,nij 几乎是不常见的单字母变量;事实上,它们几乎无处不在; k 给出,choose 是常识数学,h 不难猜,整个代码类似于 SO 上的许多伪代码。
    • @Teepeemm 说,如果我的回答中有具体内容,您需要帮助理解,请告诉我,我很乐意提供帮助。正如我所说,我并不总是喜欢在答案中将所有内容都拼出来,因为我认为自己思考和挣扎有时可能是一个很好的学习工具。
    • 我们可以同意一个完整的答案是 1 文本解释、2 编写良好的 3 代码和 4 适当的 cmets。我会说 3 是最不重要的,因为 OP 应该能够使用 1、2 或 4 中的任何一个来重建所有四个。但是仅提供 3 意味着 OP 必须对其进行逆向工程(我们同意这会很棒),或将其用作黑匣子(我们同意这会很糟糕)。如果您想为 OP 留下线索,我建议使用 1、2 或 4,而不是 3。(我会将伪代码归类为 2 而没有 3:它不会编译,但您可以通过阅读它来重构它的所有内容。 )
    • @Teepeemm 感谢您解释您的观点。我认为我衡量答案是否“完整”的方法可能比你的更直观、更离散,也更难用语言解释。在这种情况下,答案对我来说似乎是完整的,但我很乐意尝试帮助您解决您遇到困难的任何具体问题。 (我还认为您可能正在应用一个不平等的标准 - 阅读:选择这个答案 - 因为关于 SO 有这么多独特、有趣和高度投票的答案,与您评论中的标准相去甚远。)
    【解决方案5】:

    正如其他人所注意到的,您实际上并不需要子字符串列表。因为您只关心相等的子字符串,所以您只需要计算子字符串出现的次数,并且可以使用哈希/字典/映射来跟踪它。那么,当一个子串出现n 次时,准确选择k 相等子串的方法的数量就是二项式系数c(n,k)。您可以将每个不同子串的所有这些二项式系数相加,然后您就有了答案。

    请注意,如果您针对多个 k 值询问此问题,则只需构建哈希/字典/映射一次。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 2019-06-22
      • 1970-01-01
      • 1970-01-01
      • 2015-03-12
      相关资源
      最近更新 更多