尽量减少映射<字符串、字符串的连续相等提取次数>

Minimize the number of consecutive equal extractions in a deque of map<string, string>

本文关键字:字符串 提取 gt 连续 映射 lt      更新时间:2023-10-16

我希望这个地方是解决这类问题的最好地方。

我有以下问题(我认为比它看起来更复杂)。

我使用双端队列(deque)数据结构的字符串。双端队列& lt;

deque只包含N个不同的字符串,每个字符串以随机顺序重复M次,因此deque的长度为N*M,例如,假设M=4, N=2, string1="A", string2="B":

extractions[1] = "A"
extractions[2] = "A"
extractions[3] = "B"
extractions[4] = "B"
extractions[5] = "A"
extractions[6] = "B"
extractions[7] = "B"
extractions[8] = "A"

我正在寻找一种算法,它允许我找到一个有趣的配置,其中不存在两个连续相等的元素,在这种情况下,应该只有两个解,"A","B","A","B","A","B"answers"B","A","B","A","B","A","B","A","B"。对于"有趣的"配置,我指的不是简单地由N个嵌套循环给出的配置。

我实施的一个非常愚蠢的解决方案是用std::random_shuffle随机洗牌,直到没有发现连续相等的元素,但这既愚蠢又缓慢,这更像是一个bogosort…

显然最大化字符串之间的编辑距离应该更好。一些提示吗?

从一个简单的配置开始,例如对于N=4和M=4,从

开始

A B C D A B C D A B C D A B C D A B C D A B C D

,然后运行标准的洗牌算法,但要注意不能将两个相等的元素放在彼此旁边,即

for i = 0 .. N*M - 2
  let j = random(N*M - 2 - i) + i + 1
    if ((i == 0 || array[i - 1] != array[j])
        && (array[i + 1] != array[j])
        && (array[i] != array[j - 1])
        && (j == N*M - 1 || array[i] != array[j + 1]))
      swap (array[i], array[j])

这将很快为您留下一个随机配置,满足您不需要两个连续相等的元素。

int total = m * n;
for (int i = 1; i < total - 1; i++)
  {
    int j = total - 1;
    while ((j > i) && (queue[i - 1] == queue[j]))
      j--;
    if (queue[i - 1] == queue[j])
      {
        String aux = queue[i - 1];
        queue[i - 1] = queue[j];
        queue[j] = aux;
      }
  }

这段代码没有经过测试,但是您可以理解。

我会用递归来做:

的例子是在c#中:我发现它比嵌套循环更"说话":

public List<String> GetPermutations(string s, IEnumerable<String> parts, string lastPart, int targetLength)
{
    List<String> possibilities = new List<string>();
    if (s.Length >= targetLength)
    {
        possibilities.Add(s);
        return possibilities;
    }
    foreach (String part in parts)
    {
        if (!part.Equals(lastPart))
        {
            possibilities.AddRange(
               GetPermutations(s + part, parts, part, targetLength));
        }
    }
    return possibilities;
}

用法:

List<String> parts = new List<String>() { "A", "B", "C"};
int numOccurences = 4;
List<String> results = 
    GetPermutations("", parts, "", numOccurences * parts.Count );

但是如果你只想要一个可能的解决方案(当然这是更快的计算方式):

它将创建一个随机的,非平凡的解决方案,如:CACBCBCABABACAB (for a, B, C)

public String GetRandomValidPermutation(
     string s, 
     List<String> parts, 
     string lastPart, 
     int targetLength)
{
    if (s.Length >= targetLength)
    {
        return s;
    }
    String next = String.Empty; 
    while(
      (next = parts[new Random().Next(0, parts.Count)])
      .Equals(lastPart)
    ){}
    return GetRandomValidPermutation(s + next, parts, next, targetLength);
}

调用:

String validString = 
    GetRandomValidPermutation("", parts, "", numOccurences * parts.Count);