【问题标题】:Getting number of possible anagrams from a generic string, need a fast solution从通用字符串中获取可能的字谜的数量,需要一个快速的解决方案
【发布时间】:2021-07-23 12:37:14
【问题描述】:

我目前正在处理一项任务,我需要编写一个小程序,该程序将采用通用字符串,并应输出可以从字符串生成多少个可能的字谜。 作为输入的字符串最长可达 100 个字符,并且可以包括小写和大写,在这种情况下,小写和大写都被认为是不同的。输出应该只有多少种可能的组合,所以我不需要输出实际的字谜。最大时间限制是每个字符串1秒。

我已经尝试了许多不同的方法来做到这一点,但一个结论是这应该可以使用某种类型的数学算法来解决。

我尝试过的最新代码是这样的:

static void Main(string[] args)
{
    string line;
    while ((line = Console.ReadLine()) != null)
    {
        var uniqueStringArr = removeDuplicates(line);

        Console.WriteLine(countDistinctPermutations(new string(uniqueStringArr)));
    }
}

private static char[] removeDuplicates(string line)
{
    var list = line.ToList();

    return list.Distinct().ToArray();
}

static int MAX_CHAR = 100;

// Utility function to find factorial of n. 
static int factorial(int n)
{
    int fact = 1;
    for (int i = 2; i <= n; i++)
        fact = fact * i;

    return fact;
}

// Returns count of distinct permutations 
// of str. 
static int countDistinctPermutations(String str)
{
    int length = str.Length;

    int[] freq = new int[MAX_CHAR];

    // finding frequency of all the lower case 
    // alphabet and storing them in array of 
    // integer 
    for (int i = 0; i < length; i++)
        if (str[i] >= 'a')
            freq[str[i] - 'a']++;

    // finding factorial of number of appearances 
    // and multiplying them since they are 
    // repeating alphabets 
    int fact = 1;
    for (int i = 0; i < MAX_CHAR; i++)
        fact = fact * factorial(freq[i]);

    // finding factorial of size of string and 
    // dividing it by factorial found after 
    // multiplying 
    return factorial(length) / fact;
}

问题是这段代码没有为我所有的测试用例给出正确的答案。 为我提供了以下示例数据:

输入字符串 |可能的字谜数

在 | 2

考验 | 5040

abcdefghijklmnopqrstuvwxyz | 403291461126605635584000000

abcdefghijklmabcdefghijklm | 49229914688306352000000

abcdABCDabcd | 29937600

我的代码修复了前两个示例,但我得到了其他 3 个完全不同的数字。

有没有人可以帮助我解决这个问题,因为我的想法已经不多了?

/安德烈亚斯

【问题讨论】:

  • 嗨,我不明白这里的输出。如果我们看每个(2个字符)2! =2 ,考验 7! = 5040,字母 26! = 403291461126605635584000000,那么中间的那个13! (取出重复项)= 6227020800,最后一个 8! (如果考虑上下不同)= 40320
  • 我能想到的最简单的失败测试用例是“aab”
  • 您可能要考虑使用 int64 而不是 int no?如果您超过 int.MaxValue,不确定您的代码是否会中断。我试过 int I = int.MaxValue; i+i 返回 -2 :)
  • @Richard 中间那个是 26!/2^13 = 4.9229915e+22。
  • 是的,我看到问题是我使用了错误的类型,但是由于字符串最多可以有 100 个字符长 int64 是不够的,所以我改为加倍,但输出仍然是错误,因为我在转换为字符串时得到了科学记数法,有人知道将双精度数转换为大的非十进制数字字符串的好方法吗?

标签: c#


【解决方案1】:
static BigInteger Factorial(long x)
{
    return x <= 1 ? 1 : x * Factorial(x-1);
}

private static BigInteger NumberOfDistinctPermutationOf(string str)
{
    BigInteger dividend = Factorial(str.Length);

    foreach (char chr in str)
    {
        dividend /= Factorial(str.Count(c => c == chr));
        str = str.Replace(chr.ToString(), string.Empty);
    }

    return dividend;
}

说明:

  • BigIntegerStruct:表示任意大的有符号整数。

  • Enumerable.Count 方法:返回一个数字,表示指定序列中有多少元素满足条件。

  • String.Replace(String, String) 方法:返回一个新字符串,其中当前实例中出现的所有指定字符串都替换为另一个指定字符串。

  • GetNumberOfDistinctPermutation 方法:将字符串长度的阶乘除以char 出现次数的阶乘,然后针对字符串中的每个char 删除所有出现的char

【讨论】:

    【解决方案2】:
    static void Main(string[] args)
    {   
        string line;
        while ((line = Console.ReadLine()) != null)
        {
            Console.WriteLine($"{line} -> {countDistinctPermutations(line)}");
        }
    }
    static BigInteger factorial(int n)
    {
        double fact = 1;
        for (int i = 2; i <= n; i++)
            fact = fact * i;
        return fact;
    }
    static BigInteger countDistinctPermutations(String str)
    {
        // get a collection of {letter,occurences}
        var duplicates = Array.GroupBy(p => p).Select(x => new { x.Key, count = x.Count() }).Where(x => x.count > 1);
        BigInteger result = factorial(str.Length);
        // foreach letter where occurence > 1 divide total permutations by the permutations for the occurence value (occurrence!)
        foreach (var d in duplicates)
        {
            result /= factorial(d.count);
        }
        return result;
    }
    

    【讨论】:

      【解决方案3】:

      我只写了一周的代码,所以它不是很漂亮,但它可以 100% 工作。

      static void Main(string[] args)
      {
          string inputData = Console.ReadLine();
          Console.WriteLine(Solution(inputData));
      }
      static char[] convert(string text) // converting string to char[]
      {
          char[] newString = new char[text.Length];
          for (int i = 0; i < text.Length; i++)
          {
              newString[i] = text[i];
          }
          return newString;
      }
      static double CalculateFctorial(double number) // calc. factorial
      {
          double factorial = 1;
          for (int i = 1; i <= number; i++)
              factorial *= i;
          return factorial;
      }
      static int CountOcc(string text, char zet) // counting occurrences
      {                     
          int count = 0;
          for (int i = 0; i < text.Length; i++)
          {
              if (text[i] == zet)
              {
                  count++;
              }
          }
          return count;
      }
      static double Solution(string text) // the soluton, counting occurences of
                                          // each char in string and each factorial
      {
          double net = 0;
          double sol = 1;
          char[] newText = convert(text);
          for (int i = 0; i <= newText.Length; i++)
          {
              if (text.Length > 0)
              {
                  net = CountOcc(text, newText[i]);
                  sol = sol * CalculateFctorial(net);
      
                  if (newText[i] == text[0])
                  { text = text.Trim(text[0]); }
              }
          }
          double solution = CalculateFctorial(newText.Length) / sol;
          return solution;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-01
        • 1970-01-01
        • 2020-02-20
        • 1970-01-01
        • 2011-07-27
        • 2020-05-14
        • 1970-01-01
        • 2015-03-01
        相关资源
        最近更新 更多