我正在阅读this question,其中描述了以下问题陈述:
您有两个整数:
N
和K
。 Lun the dog对满足以下条件的字符串感兴趣:
- 该字符串包含完全
N
个字符,每个字符都是' A'或者' B'。- 字符串
s
完全K
对(i, j)
0 <= i < j <= N-1
),s[i] = 'A'
和s[j] = 'B'
。如果存在满足条件的字符串,请查找并返回任何此类字符串。否则,返回一个空字符串
我觉得这个问题等同于:
确定是否存在
0...N-1
的任何2个分区,其中笛卡尔积恰好包含K
元组(i, j)
i < j
元组元素表示字符串A
和B
的字符串索引的赋值。
这产生了非常幼稚(但正确)的实现:
0...N-1
(i, j)
i < j
的数量
K
这是JS中的一个实现:
const test = ([l, r]) =>
cart(l, r).reduce((p, [li, ri]) => p + (li < ri ? 1 : 0), 0) === k
const indices = _.range(0, n)
const results = partitions(indices).filter(test)
您可以在原始问题here的上下文中测试结果。 n = 13
,k = 29
的一些示例输出:
"aababbbbbbbbb", "babaaabbbbbbb", "baabababbbbbb", "abbaababbbbbb", ...
这里的第一步的复杂性就是分配集合的方式的数量:对于S(n, k)
来说,这是相当令人生畏的Stirling number of the second kind k = 2
:
例如n=13
这适用于4095
,这不是很好。
显然,如果我们只需要一个满足要求的单个分区(这是原始问题所要求的),并且懒惰地计算所有内容,我们通常不会进入最坏的情况。但总的来说,这里的方法似乎仍然非常浪费,因为我们计算的大多数分区都不满足k
中笛卡尔积中i < j
元组的属性。
我的问题是,是否有一些进一步的抽象或同构可以被识别,以使其更有效。例如。是否有可能构建一个2分区的子集,以便通过构造满足笛卡尔积的条件?
答案 0 :(得分:1)
(这是一种算法构建所有解决方案的方法;您可能正在寻找更多数学方法。)
在链接问题的this answer中,我给出了一种查找按字典顺序最小的解决方案的方法。这告诉您可以构建解决方案的B的最小数量。如果您转动方法并从一个所有B的字符串开始并从左侧添加A,您可以找到可以构建解决方案的最大B数。
要为此范围内的特定数量的B构建所有解,您可以再次使用递归方法,但不是仅添加B到结尾并使用N-1递归一次,您需要添加B,然后学士学位,然后是BAA ......并对所有将产生有效解决方案的案例进行递归。再次考虑N = 13和K = 29的例子,其中B的最小数量是3,最大值是10;您可以构建所有解决方案,例如4 B是这样的:
N=13 (number of digits)
K=29 (number of pairs)
B= 4 (number of B's)
(13,29,4)=
(12,20,3) + "B"
(11,21,3) + "BA"
(10,22,3) + "BAA"
此时你知道你已经到了将产生解决方案的案件的最后,因为(9/2) 2 &lt; 23.因此,在每个级别,您都可以使用:
N = N - length of added string
K = K - number of A's still to be added
B = B - 1
当达到B为1或N-1的递归级别时,您可以构造字符串而无需进一步递归。
实际上,你所做的是你从尽可能多的B开始,然后一个接一个地向左移动它们,同时通过向右移动其他B来补偿它,直到你已经到达B的位置尽可能多的左侧。请参阅此代码段的输出:
function ABstring(N, K, B, str) {
if ((N - B) * B < K) return;
str = str || "";
if (B <= 1 || B >= N - 1) {
for (var i = N - 1; i >= 0; i--)
str = (B == 1 && i == K || B == N - 1 && N - 1 - i != K || B == N ? "B" : "A") + str;
document.write(str + "<br>");
} else {
var prefix = "B";
--B;
while (--N) {
if (K - (N - B) >= 0 && B <= N)
ABstring(N, K - (N - B), B, prefix + str);
prefix += "A";
}
}
}
ABstring(13, 29, 4);
如果对B的所有值运行此代码从3到10,则得到(N,K)=(13,29)的所有194个解。您可以为B的所有值从0到N运行此算法,而不是计算B的最小和最大数量(并且一旦您不再获得解决方案就停止)。
这是(N,K,B)=(16,24,4)的模式:
答案 1 :(得分:0)
令P为函数,对于给定的AB字符串,返回良好对(i, j), s[i] = 'A', s[j] = 'B'
的数量。
首先考虑长度N
的字符串,其中B's
的数量是固定的,比如说b
。包含(N-b)
A's
的字符串。调用这组字符串S_b
。 S_b
上的最小值为0,左侧全部为B's
(称为此字符串O
)。 S_b
上的最高P为b*(N-b)
,所有B's
都在右侧。这是对s
中S_b
不存在所需属性的简单检查。
考虑交换邻居BA
的操作 - &gt; AB
。该操作会更改+1
的P.仅使用该操作(从字符串O
开始)可以使用b
B's
构造每个字符串。如果b*(N-b) >= K
s
S_b
B
中的O
具有必需属性,则会为我们提供此信息。
N-b
中最右边的B's
可以移动到字符串B
位置的末尾。由于无法交换两个B
,因此最右边B
左侧的B's
可以移动到最右边m_i
,...移动次数{{ 1}}(0 <= m_1 <= m_2 <= ... <= m_b <= N-b
)可以制作s
。
这样,找到长度N
的所有AB字符串b
B's
P(s)=K
其中K
等同于查找整数{{1}的所有分区最多b
部分,其中部分为<= N-b
。要查找所有字符串,需要检查所有b
b*(N-b) >= K
。