我在TopCoder上执行AB problem,我的代码传递了除一个以外的所有系统测试用例。这是问题陈述:
您有两个整数:
N
和K
。 Lun the dog对满足以下条件的字符串感兴趣:
- 该字符串包含完全
N
个字符,每个字符都是' A'或者' B'。- 字符串
s
完全K
对(i, j)
0 <= i < j <= N-1
),s[i] = 'A'
和s[j] = 'B'
。如果存在满足条件的字符串,请查找并返回任何此类字符串。否则,返回一个空字符串
我的算法是从包含所有N
s的长度为A
的字符串开始。最初,对的数量为0.如果对的数量小于K
,则遍历字符串。我从字符串末尾开始用B替换最右边的As。如果对的数量大于K
,那么我用字符串替换字符串开头的As。任何给定时间的对数为countOfAs * countOfBs
。
string createString(int n, int k) {
string result(n, 'A'); // "AAAA....A"
int i = 0, j = n - 1; // indexes to modify the string
int numPairs = 0; // number of pairs
int countA = n; // count of As in the string
int countB = 0; // count of Bs in the string
do {
if (numPairs > k) {
result[i++] = 'B';
}
else if (numPairs < k) {
result[j--] = 'B';
countB++;
}
else {
return result;
}
countA--;
numPairs = countA * countB;
} while (numPairs != 0); // numPairs will eventually go to 0 as more Bs are added
return "";
}
对我失败的测试用例是N=13, K=29
。 K
为素数,countOfAs * countOfBs
等于K
。
示例答案给出了"AAAABBBBBBABA"
作为答案(因为你可以从前4个As,前6个B,第二个到最后一个A和最后一个B,即4*6 + 4*1 + 1*1=29
)成对
答案 0 :(得分:2)
这是一个递归方法,它创建一个B数最少的解决方案:
从所有A的字符串开始,找到最靠近的位置,B放置最多K对;例如:
N=13, K=29
0123456789ABC
aaaaaaaaaaaab <- position 12 creates 12 pairs
然后递归N =位置,K = K - 位置+ #B = 18和#B = 1,其中#B是到目前为止添加的B的数量。在以下步骤中,在位置X中添加B将添加X对,但也减少已经添加的B由#B创建的对的数量;这就是为什么我们在每一步都用#B增加所需的对K的原因。
N=12, K=18, #B=1
0123456789AB
aaaaaaaaaaab <- position 11 adds 11 pairs
然后递归,N = 11,K = K - 11 + #B = 9,#B = 2:
N=11, K=9, #B=2
0123456789A
aaaaaaaaaba <- position 9 creates 9 pairs
我们已达到所需对的确切数量,因此我们可以停止递归,完整的解决方案是:
aaaaaaaaababb
如您所见,每个递归级别只有两种情况:K = N并且在递归之前将B添加到末尾,或者K <1。 N和B放在位置K处,这就完成了解决方案。
如果添加N / 2 B并且K的值仍然大于零,则没有有效的解决方案;但你可以通过检查(N / 2) 2 是否小于K来预先检查。
function ABstring(N, K, B) {
if (B == undefined) { // top-level recursion
if ((N / 2) * (N / 2) < K) return ""; // return if impossible
B = 0;
}
if (K >= N) return ABstring(N - 1, K - (N - 1) + B + 1, B + 1) + 'B';
var str = "";
for (var i = 0; i < N; i++) str += (K && i == K) ? 'B' : 'A';
return str;
}
document.write(ABstring(13, 29));
我最初将这种方法创建的解决方案描述为字典上最小的,但这并不是真的正确。它创建了一个B数最少的解决方案,并将每个B放在最右边的位置,但是这样的解决方案:
aaaabaaaabbbb
当然可以通过将第一个B向右移动并通过向左移动第二个B进行补偿来使字典缩小:
aaaabaaaabbbb
aaaaabaababbb
aaaaaabbaabbb
这种转换当然可以很容易地融入算法中。
答案 1 :(得分:1)
您可以注意到,可以通过构建以下字符串为[0, N-1]
中的任何K值形成字符串:
B B B ... A B ... B
^
index: N-1-K
您可以使用两个A
:
A B B ... A B ... B
^
index: (N-1)-(K-(N-2)) = 2N-3-K
此方案可以生成[N, 2N-4]
中的所有K值。
如果您使用p
As
,则可以通过左侧K
[(p-1)*(N-p), p*(N-p)]
和{1}}在(p-1)
中生成As
的所有值A
从右向左移动。
例如,如果N=19
和K=23
,您可以使用字符串:
A B B ... A B B B B B B
^
index: 2N-3-K = 38-3-23 = 12
答案 2 :(得分:1)
有一个简单的数学解决方案,可根据所需的字符串长度产生最佳答案:
for a given pair of positive integers, (a,b),
the highest product achievable when
sum(a,b) is fixed is when a ≈ b since
a^2 is necessarily greater than (a+1)*(a-1)
现在我们的问题很容易归纳为:
a*b + a_0*b_0 + a_1*b_1 ... = K,
where a + b + a_0 + a_1 ... <= N
(meaning only the first b term is included in the second sum)
但任何数字K
都可以表示为
K = p*p' + 1*m, where p ≈ p' and m <= max(p, p')
此表达式最小化固定总和
p + p' + 1
(remember the 1*m represents our a_0*b_0 above,
where only the a_0 is summed and b_0, which is m, is ignored)
所以需要最少字符串长度的解决方案是:
let A = round(sqrt(K))
let B = floor(K / A)
let M = remainder(K / A)
min(A,B) 'a's
followed by max(A, B) 'b's
with an additional 'a' inserted M 'b's back
for a total of A + B + 1 characters
(the rest can be filled with 'a's)
示例:
N = 13
K = 29
A = round(sqrt(29)) = 5
B = floor(29 / 5) = 5
M = remainder(29 / 5) = 4
aaaaa
aaaaabbbbb
aaaaababbbb (5 + 5 + 1 = 11 characters)
<--M 'b's back
Solution: aaaaababbbbaa