查找分隔的字符串中的所有组合

时间:2016-06-01 19:13:00

标签: c# string

我试图在c#中的所有组合中记住这个想法:

给定foo这样的字符串,我希望得到一个List<string>的值:

f o o
fo o
foo
f oo

正如你所看到的那样,并不像获取所有子字符串那么容易,而是将所有字符串都用空格分隔。

我尝试过这样的事情:

List<string> result = new List<string>();
string text = "foo";
for (int i = 1; i < foo.Lenght; i++) 
{
    //I'm stucked --> everything I think is too stupid and I don't know how to procede or not fast enough. I'm really stuck.
}

编辑: 有一些正确的答案,但很明显,他们中的任何一个都不会做,因为我正在使用的字符串各有55到85个字符,所以这意味着答案中的最佳功能会给我在2 ^ 54和2 ^ 84种可能的组合之间的东西,这只是有点太多了。

现在很清楚,找到所有的组合,之后与他们做一些事情不会做。我不得不放弃它。

6 个答案:

答案 0 :(得分:5)

这是另一个需要考虑的递归解决方案:

private static IEnumerable<string> Permute(string target) {
   if (target.Length <= 1) {
        yield return target;
        yield break;
    }
    var c = target[0];
    foreach (var rest in Permute(target.Remove(0, 1))) {
        yield return c + rest;
        yield return c + " " + rest;
    }
}

对于您的测试字符串产生所需的结果。基本上我们以递归的方式组合第一个字符+空格或没有空格+字符串的其余部分(没有第一个字符)。

要获取列表,只需执行Permute("foo").ToList();

对于“abcde”字符串,结果为:

abcde
a bcde
ab cde
a b cde
abc de
a bc de
ab c de
a b c de
abcd e
a bcd e
ab cd e
a b cd e
abc d e
a bc d e
ab c d e
a b c d e

答案 1 :(得分:4)

首先要做的事情是:如果字符串长度为 n ,则输出 2 ^ n 字符串。 所以,如果你想处理长度为70的字符串,你就会遇到问题。

您可以使用计数器,从 0 枚举到 2 ^ n ,并将其视为按位掩码:如果第一位为1,则放置一个空格在第一个和第二个字符之间,如果它为零,则不要。

因此,长度为64的无符号长度几乎不足以处理长度为65的字符串。

一个示例实现,没有递归(它比其他示例稍微冗长一些),但应该比其他长输入实现快得多:

    public IEnumerable<string> GetPartitionedStrings(string s)
    {
        if (s == null) yield break;

        if (s == "")
        {
            yield return "";
            yield break;
        }

        if (s.Length > 63) throw new ArgumentOutOfRangeException("String too long...");

        var arr = s.ToCharArray();
        for(ulong i = 0, maxI = 1UL << (s.Length - 1); i < maxI; i++)
        {
            yield return PutSpaces(arr, i);
        }
    }

    public string PutSpaces(char[] arr, ulong spacesPositions)
    {
        var sb = new StringBuilder(arr.Length * 2);
        sb.Append(arr[0]);

        ulong l = 1;
        for (int i = 1; i < arr.Length; i++, l <<= 1)
        {
            if ((spacesPositions & l) != 0UL) sb.Append(" ");

            sb.Append(arr[i]);
        }

        return sb.ToString();
    }

可能你可以用一点点的字段,但我们已经在数十亿字符串中,所以我会尝试重新解决这个问题。

答案 2 :(得分:3)

你可以使用递归来做,从空字符串开始,递归调用添加空格而不添加空格,并添加当前字符:

static IEnumerable<string> SplitString(string s, int max)
{
    return SplitString(s, 0, max, max);
}

private static IEnumerable<string> SplitString(string s, int idx, int available, int maxLength)
{
    if (idx == s.Length) yield return string.Empty;
    else
    {
        if (available > 0)
            foreach (var item in SplitString(s, idx + 1, available - 1, maxLength))
                yield return s[idx] + item;

        if (idx > 0)
            foreach (var item in SplitString(s, idx + 1, maxLength - 1, maxLength))
                yield return " " + s[idx] + item;
    }
}

对于abcde之类的输入,SplitString("abcde", 3)得到此输出:

abc de
abc d e
ab cde
ab cd e
ab c de
ab c d e
a bcd e
a bc de
a bc d e
a b cde
a b cd e
a b c de
a b c d e

答案 3 :(得分:3)

许多答案都提出了递归解决方案,这很好。但这是一个非递归解决方案的草图。

  • 假设您的单词有x个字母,其中x小于64。
  • 计算长n = 2 (x - 1)
  • 制作一个循环,我从0到n - 1
  • 将i分解为(x-1)低位。
  • 输出第一个字母。
  • 如果设置了第一位,则输出一个空格,否则没有空格。
  • 输出第二个字母。
  • 如果设置了第二位,则输出空格,否则不输入空格。
  • 等等。

你能实现给出草图的方法吗?

答案 4 :(得分:-1)

你可以尝试一些递归的东西。您从字符串hello开始。

对于不是空格的每个字符,如果它后面没有空格,则在字符串中的该位置添加一个并在该字符串上运行该函数。在第一次迭代中,您有:

  • h ello
  • he llo
  • hel lo
  • hell o
  • hello

重复,直到所有字符后跟空格。这会产生重复。

答案 5 :(得分:-2)

您可以做的是将字符串转换为char数组,如下所示:

char characters[] = text.toCharArray()

然后在你的for循环中迭代遍历这个数组

for (int i = 1; i < foo.Lenght; i++) 
{
    System.out.println(characters[i]);
}