无连续字母的排列数相同

Posted

技术标签:

【中文标题】无连续字母的排列数相同【英文标题】:Number of arrangements with no consecutive letter the same 【发布时间】:2017-04-25 02:47:32 【问题描述】:

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

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

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

我的方法

    使用堆的算法生成所有可能的排列并存储在一个数组中(使用堆的算法,因为它被发现更快) 使用 array_unique 函数删除了所有重复项 遍历数组,使用正则表达式 /(.)\1/ 识别相邻字母相同的字符串,并将没有相邻字母相同的字符串复制到新数组。 新数组包含所需的元素列表。

我的方法运行良好。但是,对于较大的字符串(超过 10 个字符的字符串),由于排列数量过多,会出现内存问题,因此程序无法运行。

是否有任何替代方法可以以编程方式确定这一点?

注意:

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

【问题讨论】:

PHP 可能不是您处理此类问题的最佳选择 @scottevans93,你建议任何其他语言来处理这个? 【参考方案1】:

pure 方法是暴力破解。只需以 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;

【讨论】:

【参考方案2】:

这里有一些 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。

第二个想法是使用记忆化来显着减少函数评估的数量。给定一个像PQRDDDEEEEFFFFF 这样的词,我们计算

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

然后删除字母(因为它们无关紧要)并对值进行排序:

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

【讨论】:

谢谢,它工作正常。在tutorialspoint.com/… 执行,使用各种值进行测试。这也更快。【参考方案3】:

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

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

【讨论】:

【参考方案4】:

Python

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

来源:

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

【讨论】:

以上是关于无连续字母的排列数相同的主要内容,如果未能解决你的问题,请参考以下文章

密码设置有关方法:不能相同字母,不能为连续字符

Leetcode(周赛):移除字母异位词5234,最大连续楼层数6064

Leetcode(周赛):移除字母异位词5234,最大连续楼层数6064

Leetcode(周赛):移除字母异位词5234,最大连续楼层数6064

Python正则表达式判断是否存在连续相同的两个字符,连续两个字符一模一样

java或者正则表达式如何判断字符串不是相同数字或者字母?不能全是连续数字?(最好是java)