【问题标题】:Given a string, counting the number of permutations of the string with no repetitions(and forbidden characters)给定一个字符串,计算没有重复(和禁止字符)的字符串的排列数
【发布时间】:2016-08-25 20:37:15
【问题描述】:

几个小时以来,我一直在努力解决一个算法问题。

问题的(花哨的)陈述如下:

我们的花园只有一排花。您将获得字符串花园中该行的当前内容。花园中的每个字符代表一朵花。不同的字符代表不同的颜色。相同颜色的花看起来都一样。您可以按照自己喜欢的顺序重新排列花园中的花朵。 (正式地,你可以交换你花园里的任意两朵花,你可以任意多次这样做。)你也被赋予了一个与花园长度相同的字符串。你想将花园重新排列成一个新的字符串 G,它将满足以下条件:

相邻的两朵花不会有相同的颜色。形式上,对于每个有效的 i,G[i] 和 G[i + 1] 必须不同。 对于每个有效的 i,G[i] 不能等于 forbid[i]。 令 X 为满足上述所有条件的不同字符串 G 的数量。计算并返回数字(X 模 1, 000, 000, 007)。

举个例子说明一下:X("aaabbb", "cccccc") = 2 ("ababab" and "bababa")

我一直在尝试计算字符串中有多少个字母(在示例中为 'a'->3、'b'->4),然后递归地计算不同的可能性(如果有重复则跳过或封禁信)。这些方面的内容:

using Map = std::map < char, size_t > ;
Map hist; 
std::string forbid;

size_t countRecursive(std::string s, size_t len)
{
    if (len == 0)
        return 1;

    size_t curPos = s.size() ;
    size_t count(0);

    for (auto &p : hist) {
        auto key = p.first;

        if (hist[key] == 0) continue;
        if (forbid[curPos] == key) continue;
        if (curPos > 0 && s[curPos - 1] == key) continue;

        hist[key]--;            
        count += countRecursive(s + key, len - 1);
        hist[key]++;
    }


    return count;
}

hist 和 forbid 是先前初始化的。但是,这似乎是 n!并且由于 n 可以

我并不是真的在寻找一个完整的解决方案。只是,如果您对我应该如何解决问题有任何建议,我将非常感谢!

【问题讨论】:

  • 您是在尝试计算此类安排的数量还是尝试生成它们?前者更容易。
  • 我只是想数数,但我仍然无法想到一个好的(性能方面)解决方案:/
  • @m69 我不完全相信这是正确的答案。假设我有“abcdefghijklmno”(15 个字母)并且禁止字符串都是“z”。我要15个!组合和链接中提到的算法(据我所知)将通过所有这些
  • 你的问题确实有禁止列表的额外条件。您可以使用链接中问题的想法来获得排列的总数,然后您需要找到禁止排列的数量并减去它们。

标签: string algorithm math combinatorics


【解决方案1】:

我会按如下方式处理它:您的“禁止”字符串与“花园”一样长。这意味着给定一个包含 N 个字符的字母表,每个位置 G[i] 最多可以有 N-1 个可能的字符(因为一个将被禁止)。这为您提供了一个仅受 N 限制的上限。如果该上限小于模数,则可能会导致一些有趣的考虑,但让我们继续前进。

现在一个非常基本的方法是计算组合:如果花园有 K 个字符长,则第一项 G[0] 将有 N-1 种可能性;如果禁止 [1] 不同于 G[0],则第二个 G[1] 将有 N-2 种可能性,如果禁止 [1] == G[0],则为 N-1。第三个字符 G[2] 也会有 N-2 种可能性,取决于禁止 [2] 和 G[1],依此类推。

为了清楚起见:N-2 来自这样一个事实,即在 N-1 种可能性中,必须删除另一个是字符串中它前面的字符的值,除非该字符与当前位置的禁止字符匹配.

所以如果 disabled[i+1] 总是不同于 G[i] 你有 N-1 * N-2 * N-2 * ... * N-2, K 次。这是你的下限。

现在在上限和下限之间有许多字符串,例如禁止[i+1] 仅在第二个位置等于 G[i] ;第二个和第三个;等等。所以你的字符串数是:

N-1 * N-2 * N-2 * N-2 ... K
N-1 * N-1 * N-2 * N-2 ... K
N-1 * N-1 * N-1 * N-2 ... K

以此类推,直到你有一个字符串,其中每个字符都有 N-1 种可能性。

换句话说,

N-1 * (N-2)^K-1
(N-1)^2 * (N-2)^K-2
(N-1)^3 * (N-2)^K-3

你能有多少这些字符串?这取决于 K 有多大,即你的花园有多大 :)

也就是说,假设我正确理解了这个问题。

【讨论】:

  • 如果我理解正确,您假设 forbid 包含字母表中的字符,但情况并非总是如此。在我给出的示例中,G = "aaabbb" 和 forbid = "cccccc"。
  • 另外,我不能为我的字母表插入无限的字母。例如,在同一个示例中,字母表是“ab”,但我可以处理 3 个“a”和 3 个“b”
  • @GiuseppeRossini 那么你如何验证For each valid i, G[i] must not be equal to forbid[i]?此外,有限的字母数量进一步减少了可能性(将其视为不重复的组合)
猜你喜欢
  • 1970-01-01
  • 2018-04-14
  • 2021-10-27
  • 2017-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-03
相关资源
最近更新 更多