使用K对创建二进制字符串

时间:2017-10-30 00:44:39

标签: string algorithm

我在TopCoder上执行AB problem,我的代码传递了除一个以外的所有系统测试用例。这是问题陈述:

  

您有两个整数:NK。 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=29K为素数,countOfAs * countOfBs等于K

示例答案给出了"AAAABBBBBBABA"作为答案(因为你可以从前4个As,前6个B,第二个到最后一个A和最后一个B,即4*6 + 4*1 + 1*1=29)成对

3 个答案:

答案 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

将此原则扩展为以下K值
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=19K=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