没有连续字母的安排数量

时间:2016-12-09 15:19:04

标签: php algorithm permutation

此问题与我的问题here有关。我试图以编程方式获得以下计数,以验证我的数学是否正确。

  

PQRDDDEEEEFFFFF中有多少个字母排列   没有连续的字母相同吗?

如何使用php程序确定此计数?

我的方法

  1. 使用堆算法生成所有可能的排列并存储在数组中(使用堆的算法,因为它更快找到)
  2. 使用array_unique函数
  3. 删除所有重复项
  4. 通过数组迭代,使用regexp /(.)\1/识别出相邻字母相同的字符串,并将没有相邻字母的字符串复制到新数组中。
  5. 新数组包含所需的元素列表。
  6. 我的方法很好。但是,对于大字符串(超过10个字符的字符串),由于大量的排列而导致内存问题,因此程序无法正常工作。

    有没有其他方法可以通过编程方式确定?

    注意:

    我只查找计数而不是字符串列表

4 个答案:

答案 0 :(得分:2)

您可以重新定义为图形问题。该图将为您的集合“PQRDDDEEEEFFFFF”中的每个字母提供节点,并且不允许自循环路径返回到相同的字母或表示相同字母的节点之间。然后,您将通过图形枚举长度为15的所有非循环路径。这应该会显着减少代码的内存占用量,并且不会生成任何需要丢弃的连续字母的“单词”。通过快速谷歌搜索,我在网上找到了一些不同的图形遍历算法。你可以很快调整一个用途。

为了显着提升性能,您可以采用记忆策略。即,从一个'F'开始,来自其他'F'节点的排列是相同的,并且子路径也是如此。有一些骑士的巡回算法带有记忆,也可以很好地适应这个问题。

答案 1 :(得分:1)

<强>的Python

Python是最受欢迎的开源(免费)语言之一,用于处理大数据所需的大型复杂数据集。它近年来变得非常流行,因为它既灵活又相对容易学习。与大多数流行的开源软件一样,它也有一个庞大而活跃的社区,致力于改进产品并使其受到新用户的欢迎。免费的Code Academy课程将在13个小时内带您完成基础知识。

来源:

http://www.datasciencecentral.com/profiles/blogs/ten-top-languages-for-crunching-big-data https://www.continuum.io/why-python

答案 2 :(得分:1)

这里有一些比你的方法更有效的Python,虽然仍然是指数级的(对不起,不懂PHP):

from collections import Counter


def instancekey(letters):
    return tuple(sorted(Counter(letters).values()))


memo = {}


def permcount(letters):
    if not letters:
        return 1
    key = instancekey(letters)
    count = memo.get(key)
    if count is None:
        count = 0
        for letter, lettercount in Counter(letters).items():
            rest = letters
            for i in range(lettercount):
                j = rest.find(letter)
                rest = rest[:j] + rest[j + 1:]
                if i % 2 == 0:
                    count += permcount(rest)
                else:
                    count -= permcount(rest)
        memo[key] = count
    return count

这里有两个想法。第一种是通过包含 - 排除递归地执行计数。对于输入中的每个字母,我们累计以该字母开头的可能性的数量。天真地,它足以计算剩余字母的可能性,但这并没有强制执行前两个字母相等的约束。因此,我们应用校正 - 减去删除两个字母的可能性的数量。这种修正本身需要修正,于是我们到达inclusion-exclusion formula

第二个想法是使用memoization来显着减少功能评估的数量。给定PQRDDDEEEEFFFFF之类的单词,我们会计算

P: 1
Q: 1
R: 1
D: 3
E: 4
F: 5

然后放下字母(因为它们不重要)并对值进行排序:

1,1,1,3,4,5.

答案 3 :(得分:0)

方法是强制它。只计算基数N,其中N是不同字母的数量。基数N数所需的位数仅为字母总数。然后对每个允许的字母数量应用约束,而不是连续两个相同。

它不漂亮而且不快,但它会给出正确答案。

这是PHP:

$letters = 'PQRDDDEEEEFFFFF';

$letter_counts = CountLetters($letters);

echo CountCombinations($letter_counts);

function CountLetters($letters) {
    $letter_counts = array();
    foreach (str_split($letters) as $letter) {
        if (isset($letter_counts[$letter])) {
            $letter_counts[$letter]++;
        } else {
            $letter_counts[$letter] = 1;
        }
    }
    return array_values($letter_counts);
}

function CountCombinations($allowable) {
    $max = count($allowable) - 1;
    $total_places = 0;
    for ($index = 0; $index <= $max; $index++) {
        $total_places += $allowable[$index];
    }

    $counter = array_fill(0, $total_places, 0);

    $combinations = 0;
    do {
        $ok = true;

        // count the number of each character in this combination
        $bins = array_fill(0, $max + 1, 0);
        for ($index = 0; $index < $total_places; $index++) {
            $bins[$counter[$index]]++;
        }

        // ensure the counts match the number allowable for each
        for ($index = 0; $index <= $max; $index++) {
            if ($bins[$index] != $allowable[$index]) {
                $ok = false;
                break;
            }

        }

        // ensure that no two consecutive are the same
        if ($ok) {
            for ($index = 0; $index <= ($total_places - 2); $index++) {
                if ($counter[$index] == $counter[$index + 1]) {
                    $ok = false;
                    break;
                }
            }
        }

        if ($ok) {
            $combinations++;
        }

        // find the next combination (i.e. count in base N)
        for ($index = 0; $index <= ($total_places - 1); $index++) {
            $counter[$index] = $counter[$index] + 1;
            if ($counter[$index] <= $max) {
                break;
            } else {
                $counter[$index] = 0;
            }
        }
    } while ($index < $total_places);

    return $combinations;
}