带字符替换的字符串组合
String Combinations With Character Replacement
我正在尝试处理一个我以前从未见过的场景,并且正在努力想出一种算法来正确地实现它。我的部分问题是对正确术语的模糊回忆。我相信我需要的是标准 "combination" 问题的变体,但我很可能会离开那里。
场景
给定一个示例字符串 "100"
(我们称它为 x
),生成 x
的所有组合,将其中一个 0
(零)字符换成 o
(小写 o)。因此,对于 "100"
的简单示例,我希望得到以下输出:
"100"
"10o"
"1o0"
"1oo"
这需要支持具有不同数量 0
个字符的可变长度字符串,但假设 0
.
的实例永远不会超过 5 个
我有一个非常简单的算法,它适用于我的 "100"
示例,但对于任何 longer/more 复杂的东西都会崩溃:
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");
}
我有一种挥之不去的感觉递归可能是我的朋友,但我正在努力弄清楚如何在这里合并我需要的条件逻辑。
您猜对了;递归是你应对这一挑战的好帮手。这是一个简单的解决方案:
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;
}
这对我有用:
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;
}
这是一个使用递归的解决方案,您的缓冲区数组:
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
s 的情况。
最后,我们得到了几个重复项,所以我们使用 Distinct
。
你在这里不需要递归,你可以枚举你的模式并将它们视为二进制数。例如,如果您的字符串中有三个零,您将得到:
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;
}
我知道越早回答越好。但我不希望我的代码被浪费。 :)
我解决这个组合数学问题的方法是利用二进制数的工作原理。我的算法如下:
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;
}
我正在尝试处理一个我以前从未见过的场景,并且正在努力想出一种算法来正确地实现它。我的部分问题是对正确术语的模糊回忆。我相信我需要的是标准 "combination" 问题的变体,但我很可能会离开那里。
场景
给定一个示例字符串 "100"
(我们称它为 x
),生成 x
的所有组合,将其中一个 0
(零)字符换成 o
(小写 o)。因此,对于 "100"
的简单示例,我希望得到以下输出:
"100"
"10o"
"1o0"
"1oo"
这需要支持具有不同数量 0
个字符的可变长度字符串,但假设 0
.
我有一个非常简单的算法,它适用于我的 "100"
示例,但对于任何 longer/more 复杂的东西都会崩溃:
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");
}
我有一种挥之不去的感觉递归可能是我的朋友,但我正在努力弄清楚如何在这里合并我需要的条件逻辑。
您猜对了;递归是你应对这一挑战的好帮手。这是一个简单的解决方案:
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;
}
这对我有用:
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;
}
这是一个使用递归的解决方案,您的缓冲区数组:
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
s 的情况。
最后,我们得到了几个重复项,所以我们使用 Distinct
。
你在这里不需要递归,你可以枚举你的模式并将它们视为二进制数。例如,如果您的字符串中有三个零,您将得到:
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;
}
我知道越早回答越好。但我不希望我的代码被浪费。 :)
我解决这个组合数学问题的方法是利用二进制数的工作原理。我的算法如下:
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;
}