C# 如何在一个字符串中获得组的所有排列?

C# 如何在一个字符串中获得组的所有排列?,c#,pseudocode,C#,Pseudocode,这不是家庭作业,尽管看起来像是家庭作业。我一直在浏览英国计算机奥林匹克运动会的网站,发现了这个问题(问题1):。我对此感到困惑,我想看看你们是怎么想的。我想不出任何简洁的方法来将所有内容分组(在这之后检查它是否是回文足够简单,即originalString==newstring(groupedString.Reverse.SelectMany(c=>c.ToArray),假设它是一个字符数组) 有什么想法吗?谢谢 工作人员的文本: 回文是一个单词,当 颠倒的。如果一个单词的字母可以分成两个或两

这不是家庭作业,尽管看起来像是家庭作业。我一直在浏览英国计算机奥林匹克运动会的网站,发现了这个问题(问题1):。我对此感到困惑,我想看看你们是怎么想的。我想不出任何简洁的方法来将所有内容分组(在这之后检查它是否是回文足够简单,即
originalString==newstring(groupedString.Reverse.SelectMany(c=>c.ToArray)
,假设它是一个字符数组)

有什么想法吗?谢谢

工作人员的文本:


回文是一个单词,当 颠倒的。如果一个单词的字母可以分成两个或两个组 多个块(每个块包含一个或多个相邻字母)则 如果颠倒这些块的顺序,则会产生块回文 相同的块序列

例如,使用括号表示块,如下所示: 块回文:

•BONBON可归为(BON)(BON)

•洋葱可组合为(ON)(I)(ON)

•BBACBB可分为(B)(BACB)(B)或(BB)(AC)(BB)或 (B) (B)(AC)(B)(B)

请注意,(BB)(AC)(B)(B)与(B)(B)(AC)(BB)相反无效 以不同的顺序显示块


问题是如何生成所有这些组,然后检查它们是否是回文

像这样的东西给邦邦怎么样

string bonBon = "BONBON";
首先检查字符计数是否为偶数或奇数

bool isEven = bonBon.Length % 2 == 0;
现在,如果是偶数,将字符串一分为二

if (isEven)
{
   int halfInd = bonBon.Length / 2;
   string firstHalf = bonBon.Substring(0, halfInd );
   string secondHalf = bonBon.Substring(halfInd);
}
现在,如果是奇数,将字符串拆分为3个字符串

else
{
   int halfInd = (bonBon.Length - 1) / 2;
   string firstHalf = bonBon.Substring(0, halfInd);
   string middle = bonBon.Substring(halfInd, bonBon.Length - halfInd);
   string secondHalf = bonBon.Substring(firstHalf.Length + middle.length);
}
也许不完全正确,但这是一个开始。。。。 还必须添加检查,如果它实际上是一个回文。。。
祝你好运

不清楚您是想要所有可能的分组,还是只想要一个可能的分组。这是一种方法,在我的脑海中,你可能会得到一个分组:

public static IEnumerable<string> GetBlocks(string testString)
{
    if (testString.Length == 0)
    {
        yield break;
    }

    int mid = testString.Length / 2;
    int i = 0;
    while (i < mid)
    {
        if (testString.Take(i + 1).SequenceEqual(testString.Skip(testString.Length - (i + 1))))
        {
            yield return new String(testString.Take(i+1).ToArray());
            break;
        }
        i++;
    }
    if (i == mid)
    {
        yield return testString;
    }
    else
    {
        foreach (var block in GetBlocks(new String(testString.Skip(i + 1).Take(testString.Length - (i + 1) * 2).ToArray())))
        {
            yield return block;
        }
    }
}
公共静态IEnumerable GetBlocks(string testString)
{
if(testString.Length==0)
{
屈服断裂;
}
int mid=testString.Length/2;
int i=0;
而(i
如果您给它
bonbon
,它将返回
bon
。如果你给它
洋葱
它会在
上给你
i
。如果你给它
bbacbb
,它会给你
b
b
ac
这应该可以:

   public List<string> BlockPalin(string s) {
        var list = new List<string>();
        for (int i = 1; i <= s.Length / 2; i++) {
            int backInx = s.Length - i;
            if (s.Substring(0, i) == s.Substring(backInx, i)) {
                var result = string.Format("({0})", s.Substring(0, i));
                result += "|" + result;

                var rest = s.Substring(i, backInx - i);

                if (rest == string.Empty) {
                    list.Add(result.Replace("|", rest));
                    return list;
                }
                else if (rest.Length == 1) {
                    list.Add(result.Replace("|", string.Format("({0})", rest)));
                    return list;
                }
                else {
                    list.Add(result.Replace("|", string.Format("({0})", rest)));

                    var recursiveList = BlockPalin(rest);
                    if (recursiveList.Count > 0) {
                        foreach (var recursiveResult in recursiveList) {
                            list.Add(result.Replace("|", recursiveResult));
                        }
                    }
                    else {
                    //EDIT: Thx to @juharr this list.Add is not needed...
                    //    list.Add(result.Replace("|",string.Format("({0})",rest)));
                        return list;
                    }
                }
            }
        }
        return list;
    }
结果是:

  • x包含1个元素:(BON)(BON)
  • y包含1个元素:(ON)(I)(ON)
  • z包含3个元素:(B)(BACB)(B)、(B)(B)(AC)(B)(B)和(BB)(AC)(BB)
    • 这是我的解决方案(没有VS,所以我使用java实现):

      问题是如何生成所有这些组,然后检查它们是否是回文

      我注意到这不一定是最好的策略。首先生成所有组,然后检查它们是否是回文,这比只生成那些回文组效率要低得多

      但是本着回答问题的精神,让我们递归地解决问题。我将生成所有组;检查一组组是否是回文是一项练习。我还将忽略一组组至少包含两个元素的要求;这很容易检查

      优雅地解决这个问题的方法是递归推理。与所有递归解决方案一样,我们从一个简单的基本情况开始:

      空字符串有多少组?只有空分组;也就是说,分组中没有任何元素

      现在我们假设我们有一个较小问题的解决方案,并问“如果我们有一个较小问题的解决方案,我们如何使用该解决方案来解决较大问题?”

      好吧,假设我们有一个更大的问题。我们有一个包含6个字符的字符串,我们希望生成所有分组。此外,分组是对称的;第一组与最后一组大小相同。通过假设,我们知道如何解决任何较小字符串的问题

      我们解决这个问题如下。假设字符串是ABCDEF。我们从两端剥离A和F,我们解决BCDE的问题,记住我们知道如何通过假设来做,现在我们在每个解决方案前加上A和F

      BCDE的解决方案是
      (B)(C)(D)(E)、(B)(CD)(E)、(BC)(DE)、(BCDE)
      。同样,我们假设我们有较小问题的解决方案,这是我们的归纳假设。然后,我们将它们与A和F结合起来,生成ABCDEF的解决方案:
      (A)(B)(C)(D)(E)(F)、(A)(B)(CD)(E)(F)、(A)(BC)(DE)(F)
      (A)(BCDE)(F)

      我们取得了很好的进展。我们结束了吗?不。接下来我们剥离AB和EF,递归地解决CD的问题。我不想费力地去做那件事。我们结束了吗?不,我们剥离ABC和DEF,递归地解决中间空字符串的问题。我们结束了吗?不,(ABCDEF)也是一种解决方案。现在我们完成了

      我希望这个草图能激发解决方案,现在这个解决方案很简单。我们从一个助手函数开始:

          public static IEnumerable<T> AffixSequence<T>(T first, IEnumerable<T> body, T last)
          {
              yield return first;
              foreach (T item in body)
                  yield return item;
              yield return last;
          }
      
      输出是

      (A)(B)(C)(D)(E)(F)
      (A)(B)(CD)(E)(F)
      (A)(BC)(DE)(F)
      (A)(BCDE)(F)
      (AB)(C)(D)(EF)
      (AB)(CD)(EF)
      (ABC)(DEF)
      (ABCDEF)
      
      好了

      现在可以检查每个分组是否是回文,但为什么?如果前缀为
      findMatch("bonbon"); // 1
      findMatch("bbacbb"); // 3
      
          public static IEnumerable<T> AffixSequence<T>(T first, IEnumerable<T> body, T last)
          {
              yield return first;
              foreach (T item in body)
                  yield return item;
              yield return last;
          }
      
          public static IEnumerable<IEnumerable<string>> GenerateBlocks(string s)
          {
      
              // The base case is trivial: the blocks of the empty string 
              // is the empty set of blocks.
              if (s.Length == 0)
              {
                  yield return new string[0];
                  yield break;
              }
              // Generate all the sequences for the middle;
              // combine them with all possible prefixes and suffixes.
              for (int i = 1; s.Length >= 2 * i; ++i)
              {
                  string prefix = s.Substring(0, i);
                  string suffix = s.Substring(s.Length - i, i);
                  string middle = s.Substring(i, s.Length - 2 * i);
                  foreach (var body in GenerateBlocks(middle))
                      yield return AffixSequence(prefix, body, suffix);
              }
              // Finally, the set of blocks that contains only this string
              // is a solution.
              yield return new[] { s };
          }
      
              foreach (var blocks in GenerateBlocks("ABCDEF"))
                  Console.WriteLine($"({string.Join(")(", blocks)})");
      
      (A)(B)(C)(D)(E)(F)
      (A)(B)(CD)(E)(F)
      (A)(BC)(DE)(F)
      (A)(BCDE)(F)
      (AB)(C)(D)(EF)
      (AB)(CD)(EF)
      (ABC)(DEF)
      (ABCDEF)
      
      if (prefix != suffix) continue;
      
              foreach (var blocks in GenerateBlocks("BBACBB"))
                  Console.WriteLine($"({string.Join(")(", blocks)})");
      
      (B)(B)(AC)(B)(B)
      (B)(BACB)(B)
      (BB)(AC)(BB)
      (BBACBB)
      
      struct Range
      {
          public int Start, End;
          public int Length { get { return End - Start; } }
          public Range(int start, int length) { Start = start; End = start + length; }
      }
      
      static IEnumerable<Range[]> GetPalindromeBlocks(string input)
      {
          int maxLength = input.Length / 2;
          var ranges = new Range[maxLength];
          int count = 0;
          for (var range = new Range(0, 1); ; range.End++)
          {
              if (range.End <= maxLength)
              {
                  if (!IsPalindromeBlock(input, range)) continue;
                  ranges[count++] = range;
                  range.Start = range.End;
              }
              else
              {
                  if (count == 0) break;
                  yield return GenerateResult(input, ranges, count);
                  range = ranges[--count];
              }
          }
      }
      
      static bool IsPalindromeBlock(string input, Range range)
      {
          return string.Compare(input, range.Start, input, input.Length - range.End, range.Length) == 0;
      }
      
      static Range[] GenerateResult(string input, Range[] ranges, int count)
      {
          var last = ranges[count - 1];
          int midLength = input.Length - 2 * last.End;
          var result = new Range[2 * count + (midLength > 0 ? 1 : 0)];
          for (int i = 0; i < count; i++)
          {
              var range = result[i] = ranges[i];
              result[result.Length - 1 - i] = new Range(input.Length - range.End, range.Length);
          }
          if (midLength > 0)
              result[count] = new Range(last.End, midLength);
          return result;
      }
      
      foreach (var input in new [] { "BONBON", "ONION", "BBACBB" })
      {
          Console.WriteLine(input);
          var blocks = GetPalindromeBlocks(input);
          foreach (var blockList in blocks)
              Console.WriteLine(string.Concat(blockList.Select(range => "(" + input.Substring(range.Start, range.Length) + ")")));
      }