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