【问题标题】:Algorithm: Odometer / Brute force算法:里程表/蛮力
【发布时间】:2008-10-23 07:07:58
【问题描述】:

我想用 C# 风格的语言编写一个类似于里程表的方法,但不仅仅是使用 0-9 来表示字符,而是使用任何字符集。它或多或少会像一个蛮力应用程序一样。

如果我将一个字符数组从 0 传递到 J,并将长度设置为 5,我想要像 00000, 00001, 00002 这样的结果... HJJJJ,IJJJJJ,JJJJJ.

这是基础,请帮我扩展:

protected void Main()
{
    char[] chars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };

    BruteForce(chars, 5);
}

private void BruteForce(char[] chars, int length)
{
    // for-loop (?) console-writing all possible combinations from 00000 to JJJJJ
    // (when passed in length is 5)
    // TODO: Implement code...
}

【问题讨论】:

  • 哈哈,我不认为我的笔记本电脑是现代密码的现实暴力机器:) 它更适合大脑和乐趣。

标签: c# algorithm


【解决方案1】:

这不是 相当 "recursion instead of multi-loops" 的副本,但非常接近。如果这对您没有帮助,我会写一个解决方案。

编辑:这是一个非递归解决方案。递归的返回 IEnumerable<string> 稍微困难一些,但返回迭代器会提供一个很好的接口 IMO :)

private static IEnumerable<string> GetAllMatches(char[] chars, int length)
{
    int[] indexes = new int[length];
    char[] current = new char[length];
    for (int i=0; i < length; i++)
    {
        current[i] = chars[0];
    }
    do
        {
            yield return new string(current);
        }
        while (Increment(indexes, current, chars));
}

private static bool Increment(int[] indexes, char[] current, char[] chars)
{
    int position = indexes.Length-1;

    while (position >= 0)
    {
        indexes[position]++;
        if (indexes[position] < chars.Length)
        {
             current[position] = chars[indexes[position]];
             return true;
        }
        indexes[position] = 0;
        current[position] = chars[0];
        position--;
    }
    return false;
}

【讨论】:

    【解决方案2】:

    这是我找到的解决方案之一。我喜欢它的紧凑和分离:

    private static char[] characters =
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };
    
    // length: The length of the string created by bruteforce
    public static void PerformBruteForce(int length) {
        int charactersLength = characters.Length;
        int[] odometer = new int[length];
        long size = (long)Math.Pow(charactersLength, length);
    
        for (int i = 0; i < size; i++) {
            WriteBruteForce(odometer, characters);
            int position = 0;
            do {
                odometer[position] += 1;
                odometer[position] %= charactersLength;
            } while (odometer[position++] == 0 && position < length);
        }
    }
    
    private static void WriteBruteForce(int[] odometer, char[] characters) {
        // Print backwards
        for (int i = odometer.Length - 1; i >= 0; i--) {
            Console.Write(characters[odometer[i]]);
        }
        Console.WriteLine();
    }
    

    【讨论】:

      【解决方案3】:

      谷歌排列组合。

      但是,如果您只是处理“十六进制”范围,只需执行以下操作:

      for (int i = 0; i < (1 << 24); i++)
        string s = i.ToString("X6");
      

      【讨论】:

      • 我们在这里追求的并不是严格的排列——这不允许我们追求的那种重复。不幸的是,我想不出正确的词,这就是为什么我在回答中选择了平淡无奇的“GetAllMatches”方法名称。
      • 很抱歉与 0-F 混淆了,这只是为了参考我们都认识的东西。
      • 你可以用你自己的n基数代替。
      • @Jon:我认为这个词是组合:)
      • @Leppie:我也是这么想的,但事实并非如此。这需要一个集合 { A, B, C} 并返回 {}, {A}, {B}, {C}, {A, B} 等。它是无序的,具有不同的元素。嗯。
      【解决方案4】:

      下面是我之前用于此确切目的的一个类...顾名思义,它根据所提供字符集中的字符数在不同的基础中计数。希望有用...

      public class BaseNCounter
      {
          public char[] CharSet { get; set; }
          public int Power { get; set; }
      
          public BaseNCounter() { }
      
          public IEnumerable<string> Count() {
              long max = (long)Math.Pow((double)this.CharSet.Length, (double)this.Power);
              long[] counts = new long[this.Power];
              for(long i = 0; i < max; i++)
                  yield return IncrementArray(ref counts, i);
          }
      
          public string IncrementArray(ref long[] counts, long count) {
              long temp = count;
              for (int i = this.Power - 1; i >= 0 ; i--) {
                  long pow = (long)Math.Pow(this.CharSet.Length, i);
                  counts[i] = temp / pow;
                  temp = temp % pow;
              }
      
              StringBuilder sb = new StringBuilder();
              foreach (int c in counts) sb.Insert(0, this.CharSet[c]);
              return sb.ToString();
          }
      }
      

      这是控制台应用程序中的几个使用场景。

      class Program
      {
          static void Main(string[] args)
          {
              BaseNCounter c = new BaseNCounter() { 
                  CharSet = new char [] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }, 
                  Power = 2};
      
              foreach(string cc in c.Count())
                  Console.Write("{0} ,", cc);
              Console.WriteLine("");
      
              BaseNCounter c2 = new BaseNCounter()
              {
                  CharSet = new char[] { 'x', 'q', 'r', '9'},
                  Power = 3
              };
              foreach (string cc in c2.Count())
                  Console.Write("{0} ,", cc);
              Console.Read();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2015-06-22
        • 1970-01-01
        • 2015-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-08
        • 2016-04-05
        相关资源
        最近更新 更多