我正在尝试一个问题,我们被给予长度为N(<10^5)的二进制字符串,并且我们被允许在它上面恰好X(<10^5)翻转,我们被问到有多少不同的字符串是可能的?我不明白这一点,我认为它可以用dp解决,但不能用递归来解决。请帮帮忙?
示例:考虑N=3,1 1 1,X=2的二进制字符串在应用2次翻转后可以形成的新的二进制字符串是1 1 1(翻转第一/第二/第三位两次)0 0 1(翻转第一和第二位)1 0 0(翻转第二和第三位)0 10 0(翻转第一和第三位)
发布于 2016-06-10 02:20:21
查找X翻转的字符串
例如,考虑N=10、X=4和初始字符串为:
initial: 0011010111 那么这将是一个X翻转字符串的例子:
flipped: 0000111111 因为4位是不同的。如果对这两个字符串执行XOR运算,则会得到:
initial: 0011010111
flipped: 0000111111
XOR-ed: 0011101000 其中XOR-ed串中的4个设置位(1)指示已经翻转的4个位的位置。
现在倒过来想一想。如果您有一个初始字符串和一个具有4个设置位的字符串,则可以通过对它们进行异或运算来生成X翻转的字符串:
initial: 0011010111
4 bits : 0011101000
XOR-ed: 0000111111 因此,如果您生成长度为N的每个具有X个设置位的二进制字符串,并将这些位与初始字符串进行异或运算,您将得到所有X翻转的字符串。
initial 4 bits XOR-ed
0011010111 0000001111 0011011000
0000010111 0011000000
0000100111 0011110000
...
1110010000 1101000111
1110100000 1101110111
1111000000 1100010111例如,可以使用Gosper's Hack来生成具有X个设置位的所有N长度字符串。在下面的代码示例中,我使用了一个反向字典顺序函数,这是我最初为this answer编写的。
Double-flipping
如果位可以翻转两次,那么X翻转后的字符串可能不具有与初始字符串不同的X位,而只有X-2位,因为有一位被翻转,然后又被翻转回其原始状态。或者X-4,如果位被翻转了4次,或者两个不同的位被翻转了两次。实际上,不同的位数可以是X,X-2,X-4,X-6...降至1或0(取决于X是奇数还是偶数)。
因此,要生成所有X翻转的字符串,您需要生成具有X翻转比特的所有字符串,然后生成具有X-2翻转比特的所有字符串,然后生成X-4、X-6...降至1或0。
如果X> N,则为
如果X大于N,那么显然一些位将被多次翻转。生成它们的方法是相同的:从X开始,倒数到X-2,X-4,X-6...但是只生成值为≤N的字符串。所以实际上,您从N或N-1开始,这取决于X-N是偶数还是奇数。
字符串总数
具有X个翻转比特的N长度字符串的数量等于具有X个设置比特的N长度字符串的数量,这是Binomial Coefficient N choose X。当然,你必须考虑X-2,X-4,X-6的字符串...翻转的比特也是如此,所以总数是:
(N选择X) + (N选择X-2) + (N选择X-4) + (N选择X-6) + ... + (N选择(1或0))
在X大于N的情况下,根据X-N是偶数还是奇数,从N choose N或N choose N-1开始。
对于使用N=3和X=2的示例,总数为:
(3 choose 2) + (3 choose 0) = 3 + 1 = 4 对于上面使用N=10和X=4的示例,总数为:
(10 choose 4) + (10 choose 2) + (10 choose 0) = 210 + 45 + 1 = 256 对于包含N=6和X=4的另一个答案中的示例,正确的数字为:
(6 choose 4) + (6 choose 2) + (6 choose 0) = 15 + 15 + 1 = 31 示例代码
此JavaScript代码片段以相反的字典序生成二进制字符串序列(以便设置位从左向右移动),然后打印出所产生的翻转字符串和上述示例的总计数:
function flipBits(init, x) {
var n = init.length, bits = [], count = 0;
if (x > n) x = n - (x - n) % 2; // reduce x if it is greater than n
for (; x >= 0; x -= 2) { // x, x-2, x-4, ... down to 1 or 0
for (var i = 0; i < n; i++) bits[i] = i < x ? 1 : 0; // x ones, then zeros
do {++count;
var flip = XOR(init, bits);
document.write(init + " ⊕ " + bits + " → " + flip + "<br>");
} while (revLexi(bits));
}
return count;
function XOR(a, b) { // XOR's two binary arrays (because JavaScript)
var c = [];
for (var i = 0; i < a.length; i++) c[i] = a[i] ^ b[i];
return c;
}
function revLexi(seq) { // next string in reverse lexicographical order
var max = true, pos = seq.length, set = 1;
while (pos-- && (max || !seq[pos])) if (seq[pos]) ++set; else max = false;
if (pos < 0) return false;
seq[pos] = 0;
while (++pos < seq.length) seq[pos] = set-- > 0 ? 1 : 0;
return true;
}
}
document.write(flipBits([1,1,1], 2) + "<br>");
document.write(flipBits([0,0,1,1,0,1,0,1,1,1], 4) + "<br>");
document.write(flipBits([1,1,1,1,1,1], 4) + "<br>");
发布于 2016-06-08 19:43:07
这是在c#中。看看有没有帮助。
static class Program
{
static void Main(string[] args)
{
string bnryStr = "111111";
int x = 4;
//here in this string merely the poistions of the binary string numbers are placed
//if the binary string is "1111111", this fakeStr will hold "0123456"
string fakeStr = String.Empty;
for (int i = 0; i < bnryStr.Length; i++)
{
fakeStr += i.ToString();
}
char[] arr = fakeStr.ToCharArray();
// gets all combinations of the input string altered in x ways
IEnumerable<IEnumerable<char>> result = Combinations(arr, x);
// this holds all the combinations of positions of the binary string at which flips will be made
List<string> places = new List<string>();
foreach (IEnumerable<char> elements in result)
{
string str = string.Empty;
foreach (var item in elements)
{
str += item;
}
places.Add(str);
}
List<string> results = GetFlippedCombos(bnryStr, places);
Console.WriteLine("The number of all possible combinations are: " + results.Count);
foreach (var item in results)
{
Console.WriteLine(item);
}
Console.Read();
}
/// <summary>
/// Gets a list of flipped strings
/// </summary>
/// <param name="bnryStr">binary string</param>
/// <param name="placeList">List of strings containing positions of binary string at which flips will be made</param>
/// <returns>list of all possible combinations of flipped strings</returns>
private static List<string> GetFlippedCombos(string bnryStr, List<string> placeList)
{
List<string> rtrnList = new List<string>();
foreach (var item in placeList)
{
rtrnList.Add(Flip(bnryStr, item));
}
return rtrnList;
}
/// <summary>
/// Flips all the positions (specified in 'places') of a binary string from 1 to 0 or vice versa
/// </summary>
/// <param name="bnryStr">binary string</param>
/// <param name="places">string holding the position values at which flips are made</param>
/// <returns>a flipped string</returns>
private static string Flip(string bnryStr, string places)
{
StringBuilder str = new StringBuilder(bnryStr);
foreach (char place in places)
{
int i = int.Parse(place.ToString());
char ch = str[i];
str.Replace(ch, '0' == ch ? '1' : '0', i, 1);
}
return str.ToString();
}
/// <summary>
/// Gets all combinations of k items from a collection with n elements
/// </summary>
/// <param name="elements">collection having n elements</param>
/// <param name="k">no of combinations</param>
/// <returns>all possible combinations of k items chosen from n elements</returns>
private static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
{
if (k == 0)
{
return new[] { new T[0] };
}
else
{
IEnumerable<T> elements1 = elements as IList<T> ?? elements.ToList();
IEnumerable<IEnumerable<T>> enumerable = elements1.SelectMany((e, i) =>
{
IEnumerable<T> enumerable1 = elements as IList<T> ?? elements1.ToList();
return enumerable1.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c));
});
return enumerable;
}
}
}
Result:
Binary String: 111111
No. of Flips: 4
The number of all possible combinations are: 15
000011
000101
000110
001001
001010
001100
010001
010010
010100
011000
100001
100010
100100
101000
110000https://stackoverflow.com/questions/37680863
复制相似问题