最小化 map<string, string> 的双端队列中连续相等提取的数量

Posted

技术标签:

【中文标题】最小化 map<string, string> 的双端队列中连续相等提取的数量【英文标题】:Minimize the number of consecutive equal extractions in a deque of map<string, string> 【发布时间】:2011-12-02 11:20:19 【问题描述】:

我希望这个地方最适合这类问题。

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

我正在使用字符串的双端队列(deque)数据结构。 deque 提取;

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","A","B" 和 "B","A","B","A","B","A","B “,“一种”。 对于“有趣”的配置,我的意思不是简单地由 N 个嵌套循环给出的配置。

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

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

【问题讨论】:

很容易生成没有连续相同元素的配置。您是否正在寻找一个特定的配置(例如,最接近您的初始配置的配置,或者类似的配置)? 不,我对特定配置不感兴趣,唯一的问题是应该避免连续提取。显然这个例子很糟糕,但是对于 N=3,我们可以有更多有趣的例子,N=3 M=3 的可能允许配置应该是 A,B,C,B,A,C,A,B,C 而不仅仅是简单的配置:A,B,C,A,B,C,A,B,C 这种配置基本上都是我开始的,所以没什么意思。 那么你需要澄清你的问题,说明你正在寻找“有趣”的配置,并定义“有趣”的确切含义。 您提出的解决方案与bogosort 非常相似。 【参考方案1】:

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

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])

这应该会很快为您提供一个随机配置,以满足您不具有两个连续相等元素的要求。

【讨论】:

random(n) 函数应该返回什么? [0,n) 范围内的随机数?或在 [1,n] 范围内? 是的,这绝对有效,但必须应用到没有连续的。我会用一段时间( sumConsecutiveElements(array) != 0 ) yourFunction(array) 将它括起来,其中 sumConsecutiveElements(array) 是一个返回连续相等元素数量的函数。感谢您的精彩回答! 直到没有连续时才需要应用,因为算法确保在算法执行过程中的任何时刻都没有......【参考方案2】:
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;
      
  

此代码未经测试,但您明白了。

【讨论】:

在第一次实现时,此解决方案不起作用,然后辅助字符串无用,一个简单的 std::swap 可以为您完成这项工作。也许这是我的实现错误,但我用 .at() 和迭代器测试了它......【参考方案3】:

我会用递归来做:

示例在 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(用于 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);

【讨论】:

是的,但这并不能帮助我解散列表,只会产生一个简单的配置 A,B,C,A,B,C,A,B,C...我错了吗? 它返回有效组合的完整列表。从 ABA 开始...以 ZYZ 结尾...(如果是整个字母表)。

以上是关于最小化 map<string, string> 的双端队列中连续相等提取的数量的主要内容,如果未能解决你的问题,请参考以下文章

在Hashmap中获取arrayList的大小

java Map集合中如何去比较整型的Value值得最小值

599. 两个列表的最小索引总和C++

599. 两个列表的最小索引总和C++

将 Map<String,Object> 转换为 Map<String,String>

将 Map<String,String> 转换为 Map<String,Object>