【问题标题】:Calculating Nth permutation step?计算第 N 个置换步骤?
【发布时间】:2011-04-03 10:23:27
【问题描述】:

我有一个字母 a-z 的 char[26] 并通过嵌套的 for 语句生成一个序列列表,例如:

aaa, aaz... aba, abb, abz, ... zzy, zzz.

目前,该软件被编写为从 aaa-zzz 生成所有可能值的列表,然后维护一个索引,并遍历它们中的每一个对它们执行操作。

这个列表显然很大,它不是大得离谱,但它已经到了内存占用太大的地步(还有其他区域正在研究,但这是我得到的一个)。

我正在尝试生成一个公式,我可以在其中保留索引,但取消序列列表并根据当前索引计算当前序列(因为序列之间的操作之间的时间很长)。

例如:

char[] characters = {a, b, c... z};
int currentIndex = 29; // abd

public string CurrentSequence(int currentIndex)
{
    int ndx1 = getIndex1(currentIndex); // = 0
    int ndx2 = getIndex2(currentIndex); // = 1
    int ndx3 = getIndex3(currentIndex); // = 3

    return string.Format(
        "{0}{1}{2}", 
        characters[ndx1], 
        characters[ndx2], 
        characters[ndx3]); // abd
}

我尝试过使用子集 (abc) 制作一个小示例,并尝试使用模除法对其进行索引,但我今天思考困难,我被难住了。

我不是在寻求答案,只是寻求任何帮助。也许是朝着正确的方向踢?

【问题讨论】:

  • char[25] 不足以容纳 a..z。您可能想要检查缓冲区溢出或其他内容。
  • 你到底想达到什么目的?
  • 您似乎正在尝试计算排列序列的单个特定步骤,而不是索引整个排列结果?
  • 我知道答案已被接受,但这是一个很好的问题,有一组聪明的答案。我会把它留给作者,但我建议一个更好的标题,比如:“如何计算第 N 个排列步骤?” “索引到不存在的集合”并没有真正传达问题,IMO。
  • @Paul Sasik:同意。改变了。顺便说一句,我确实使用了@LBushkin 和@Martin Liversage 提供的想法的变体来解决与这个问题非常相关的问题。

标签: c# math list indexing


【解决方案1】:

提示:想一想如何打印一个以 26 为底而不是以 10 为底的数字,以及如何用字母代替数字。以任意基数显示数字的一般算法是什么?

剧透:(向右滚动查看)

                                                                                      int ndx1 = currentIndex / 26 / 26 % 26;
                                                                                      int ndx2 = currentIndex / 26 % 26;
                                                                                      int ndx3 = currentIndex % 26;

【讨论】:

    【解决方案2】:

    假设 26 个字符,这样的事情应该可以工作:

    public string CurrentSequence(int currentIndex) {
        return characters[currentIndex / (26 * 26)] 
            + characters[(currentIndex / 26) % 26]
            + characters[currentIndex % 26];
    }
    

    【讨论】:

      【解决方案3】:

      哇,two questions in one day 可以通过笛卡尔积来解决。太棒了。

      您可以使用Eric Lippert's LINQ snippet 生成索引值的所有组合。这种方法会产生一组流式值,因此它们不需要存储在内存中。这种方法很好地将生成代码的逻辑与维护状态或使用代码执行计算分开。

      Eric 的所有组合代码:

      static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)  
      {  
        IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };  
        return sequences.Aggregate(  
          emptyProduct,  
          (accumulator, sequence) =>   
            from accseq in accumulator   
            from item in sequence   
            select accseq.Concat(new[] {item}));                 
      } 
      

      你现在可以写了:

      public static IEnumerable<string> AllCodes()
      {
        char[] characters = {a, b, c... z}; 
        IEnumerable<char[]> codeSets = new[] { characters, characters, characters };
      
        foreach( var codeValues in codeSets.CartesianProduct() )
        {
          yield return 
             string.Format( "{0}{1}{2}", codeValues[0], codeValues[1], codeValues[2]);
        }
      }
      

      上面的代码生成从aaazzz 的所有代码字符串的流式序列。您现在可以在执行处理的其他地方使用它:

      foreach( var code in AllCodes() )
      {
          // use the code value somehow...
      }
      

      【讨论】:

      • 该解决方案不允许您有效地查找索引,这是用例。
      • @recursive。可能。 Excepy OP 确实表明该软件无论如何都可以通过所有索引工作。所以这可能仍然有帮助。
      • recursive 是正确的,但它确实非常有用。我看过 Eric 的帖子,但忘记了。 +1
      • 我不会说查找索引是用例。我读它是因为 OP 试图解决内存中的大列表问题,我认为使用惰性枚举器是一个更可取的解决方案,考虑到问题中定义的要求。
      【解决方案4】:

      有多种方法可以解决您的问题,但一种选择是动态生成序列,而不是将其存储在列表中:

      IEnumerable<String> Sequence() {
        for (var c1 = 'a'; c1 <= 'z'; ++c1)
          for (var c2 = 'a'; c2 <= 'z'; ++c2)
            for (var c3 = 'a'; c3 <= 'z'; ++c3)
              yield return String.Format("{0}{1}{2}", c1, c2, c3);
      }
      

      然后您可以枚举所有字符串:

      foreach (var s in Sequence())
        Console.WriteLine(s);
      

      此代码根本不使用索引,但它允许您使用简单的代码围绕字符串序列创建一个循环,而无需存储字符串。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-08
        • 1970-01-01
        • 1970-01-01
        • 2019-05-06
        • 2012-02-08
        • 1970-01-01
        • 2012-03-26
        • 1970-01-01
        相关资源
        最近更新 更多