我正在努力完成我以前没见过的场景,并且正在努力想出一个算法来正确实现这个。我的部分问题是对正确术语的朦胧回忆。我相信我需要的是标准的变化"组合"问题,但我很可能在那里。
情景
给定一个示例字符串"100"
(让我们称之为x
),生成x
的所有组合,换出其中一个0
(零)字符o
(小写o)。所以,对于"100"
的简单示例,我希望这个输出:
"100"
"10o"
"1o0"
"1oo"
这需要支持具有不同数量0
个字符的不同长度字符串,但假设0
个实例永远不会超过5个。
我有这个非常简单的算法,适用于"100"
的样本,但对于更长/更复杂的事情会分崩离析:
public IEnumerable<string> Combinations(string input)
{
char[] buffer = new char[input.Length];
for(int i = 0; i != buffer.Length; ++i)
{
buffer[i] = input[i];
}
//return the original input
yield return new string(buffer);
//look for 0's and replace them
for(int i = 0; i != buffer.Length; ++i)
{
if (input[i] == '0')
{
buffer[i] = 'o';
yield return new string(buffer);
buffer[i] = '0';
}
}
//handle the replace-all scenario
yield return input.Replace("0", "o");
}
我有一种唠叨的感觉,递归可能是我的朋友,但我正在努力弄清楚如何整合我需要的条件逻辑。
答案 0 :(得分:6)
你的猜测是正确的;递归是你挑战这个挑战的朋友。这是一个简单的解决方案:
public static IEnumerable<string> Combinations(string input)
{
int firstZero = input.IndexOf('0'); // Get index of first '0'
if (firstZero == -1) // Base case: no further combinations
return new string[] { input };
string prefix = input.Substring(0, firstZero); // Substring preceding '0'
string suffix = input.Substring(firstZero + 1); // Substring succeeding '0'
// e.g. Suppose input was "fr0d00"
// Prefix is "fr"; suffix is "d00"
// Recursion: Generate all combinations of suffix
// e.g. "d00", "d0o", "do0", "doo"
var recursiveCombinations = Combinations(suffix);
// Return sequence in which each string is a concatenation of the
// prefix, either '0' or 'o', and one of the recursively-found suffixes
return
from chr in "0o" // char sequence equivalent to: new [] { '0', 'o' }
from recSuffix in recursiveCombinations
select prefix + chr + recSuffix;
}
答案 1 :(得分:4)
这对我有用:
public IEnumerable<string> Combinations(string input)
{
var head = input[0] == '0' //Do I have a `0`?
? new [] { "0", "o" } //If so output both `"0"` & `"o"`
: new [] { input[0].ToString() }; //Otherwise output the current character
var tails = input.Length > 1 //Is there any more string?
? Combinations(input.Substring(1)) //Yes, recursively compute
: new[] { "" }; //Otherwise, output empty string
//Now, join it up and return
return
from h in head
from t in tails
select h + t;
}
答案 2 :(得分:2)
这里不需要递归,你可以枚举你的模式并将它们视为二进制数。例如,如果字符串中有三个零,则会得到:
0 000 ....0..0....0...
1 001 ....0..0....o...
2 010 ....0..o....0...
3 011 ....0..o....o...
4 100 ....o..0....0...
5 101 ....o..0....o...
6 110 ....o..o....0...
7 111 ....o..o....o...
您可以使用按位运算符或通过处理要替换的字符(如里程表)来实现它。
下面是C中的一个实现。我不熟悉C#,从其他答案中我看到C#已经有了合适的标准类来实现你想要的东西。 (虽然我很惊讶,很多人都在这里提出递归。)
因此,这更多地是我对问题的评论的解释或说明,而不是针对您的问题的实施建议。
int binrep(char str[])
{
int zero[40]; // indices of zeros
int nzero = 0; // number of zeros in string
int ncombo = 1; // number of result strings
int i, j;
for (i = 0; str[i]; i++) {
if (str[i] == '0') {
zero[nzero++] = i;
ncombo <<= 1;
}
}
for (i = 0; i < ncombo; i++) {
for (j = 0; j < nzero; j++) {
str[zero[j]] = ((i >> j) & 1) ? 'o' : '0';
}
printf("%s\n", str); // should yield here
}
return ncombo;
}
答案 3 :(得分:1)
这是一个使用递归和缓冲区数组的解决方案:
private static void Main(string[] args)
{
var a = Combinations("100");
var b = Combinations("10000");
}
public static IEnumerable<string> Combinations(string input)
{
var combinations = new List<string>();
combinations.Add(input);
for (int i = 0; i < input.Length; i++)
{
char[] buffer= input.ToArray();
if (buffer[i] == '0')
{
buffer[i] = 'o';
combinations.Add(new string(buffer));
combinations = combinations.Concat(Combinations(new string(buffer))).ToList();
}
}
return combinations.Distinct();
}
该方法将原始输入添加为第一个结果。之后,我们在循环中替换0
s,我们将其视为o
,然后使用新输入调用我们的方法,这将涵盖多个0
的情况。
最后,我们最终得到了一些副本,因此我们使用Distinct
。
答案 4 :(得分:0)
我知道早期的答案更好。但我不希望我的代码浪费掉。 :)
我对这个组合问题的方法是利用二进制数的工作方式。我的算法如下:
List<string> ZeroCombiner(string str)
{
// Get number of zeros.
var n = str.Count(c => c == '0');
var limit = (int)Math.Pow(2, n);
// Create strings of '0' and 'o' based on binary numbers from 0 to 2^n.
var binaryStrings = new List<string>();
for (int i = 0; i < limit; ++i )
{
binaryStrings.Add(Binary(i, n + 1));
}
// Replace each zero with respect to each binary string.
var result = new List<string>();
foreach (var binaryString in binaryStrings)
{
var zeroCounter = 0;
var combinedString = string.Empty;
for (int i = 0; i < str.Length; ++i )
{
if (str[i] == '0')
{
combinedString += binaryString[zeroCounter];
++zeroCounter;
}
else
combinedString += str[i];
}
result.Add(combinedString);
}
return result;
}
string Binary(int i, int n)
{
string result = string.Empty;
while (n != 0)
{
result = result + (i % 2 == 0 ? '0' : 'o');
i = i / 2;
--n;
}
return result;
}