无连续字母的排列数相同
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