找到将零插入位模式的所有方法
由于某种原因,我一直在努力解决这个问题。我有 15 位代表一个数字。这些位必须与模式匹配。该模式是按照位开始的方式定义的:它们是该模式最右对齐的表示形式。假设模式为 1 4 1。位将为:
000000010111101
因此,一般规则是,获取模式中的每个数字,创建那么多位(在本例中为 1、4 或 1),然后至少有一个空格分隔他们。因此,如果它是 1 2 6 1 (它将是随机的):
001011011111101
从右对齐版本开始,我想生成满足该模式的每个可能的数字。位的数量将存储在变量中。因此,对于一个简单的情况,假设它是 5 位,初始位模式为:00101。我想生成:
00101 01001 01010 10001 10010 10100
我正在尝试在 Objective-C 中执行此操作,但任何类似于 C 的东西都可以。我似乎无法为此想出一个好的递归算法。在上面的例子中这是有道理的,但是当我开始使用 12431 并必须跟踪所有内容时,它就崩溃了。
I've been struggling to wrap my head around this for some reason. I have 15 bits that represent a number. The bits must match a pattern. The pattern is defined in the way the bits start out: they are in the most flush-right representation of that pattern. So say the pattern is 1 4 1. The bits will be:
000000010111101
So the general rule is, take each number in the pattern, create that many bits (1, 4 or 1 in this case) and then have at least one space separating them. So if it's 1 2 6 1 (it will be random):
001011011111101
Starting with the flush-right version, I want to generate every single possible number that meets that pattern. The # of bits will be stored in a variable. So for a simple case, assume it's 5 bits and the initial bit pattern is: 00101. I want to generate:
00101
01001
01010
10001
10010
10100
I'm trying to do this in Objective-C, but anything resembling C would be fine. I just can't seem to come up with a good recursive algorithm for this. It makes sense in the above example, but when I start getting into 12431 and having to keep track of everything it breaks down.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
希望这会让您更容易理解它(请用手中的笔和纸阅读本文)。
假设零的数量(从右侧开始)为 x1、x2、...、xn。例如:如果位模式为 00001110001001,则 x1 = 0、x2 = 2、x3 = 3、x4 = 4。n 比 1 的块数多 1。请注意,知道 x1、x2、...、xn 就足以找出位模式。
现在,如果 1 的总数为 S,可用位数为 M,那么我们必须有
x1 + x2 + ... + xn = M - S
且 x1 ≥ 0,xn ≥ 0,x2 ≥ 1, x3 ≥ 1, ...
设 z1 = x1 + 1
和 zn = xn + 1
因此我们有
z1 + x2 + ... x< sub>n-1 + zn = M - S + 2
其中 z1 ≥ 1,x2 ≥ 1, x3 ≥ 1, ..., zn ≥ 1。
现在考虑 M-S+2 个项目的分区,其中每个分区至少有一个项目。任何分区都对应于上式的一个解,并且解对应于 1-1 方式的分区。
将 M-S+2 个物品沿一条线放置。要获得分区,请考虑将 n-1 根棍子放置在物品之间的 M-S+2-1 = M-S+1 可用位置中。
因此,解决方案(以及最终您所需的位模式)唯一对应于在 M-S+1 个点中选择 n-1 个点的方式。
在 5 位的情况下,1 位为 1 和 1。
您有 n = 3、M = 5 和 S = 2。
因此您有 M-S+1 选择 n-1 = 4 选择 2 = 6 种可能性。
枚举 n 选择 r 组合是一个标准问题,您应该在网络上找到各种各样的解决方案(其中一些非常聪明!)。
有关示例,请参见此处: http://compprog.files.wordpress.com/ 2007/10/comb1.c 似乎支持“惰性”枚举:next_combination 并且不需要大量内存。
Hopefully, this will make it easier to wrap your head around it (please read through this with a pen and paper in hand).
Say the number of zeroes (starting from the right) is x1, x2, ..., xn. eg: if the bit pattern is 00001110001001 then x1 = 0, x2 = 2, x3 = 3, x4 = 4. n is one more than the number of blocks of ones. Observe that knowing x1, x2, ..., xn is enough to figure out the bit-pattern.
Now if the total number of 1's you have is S and total number of bits you have available is M then we must have that
x1 + x2 + ... + xn = M - S
and x1 ≥ 0, xn ≥ 0, x2 ≥ 1, x3 ≥ 1, ...
Let z1 = x1 + 1
and zn = xn + 1
Thus we have
z1 + x2 + ... xn-1 + zn = M - S + 2
Where z1 ≥ 1, x2 ≥ 1, x3 ≥ 1, ..., zn ≥ 1.
Now consider a partition of M-S+2 items where each partition has at least one item. Any partition corresponds to a solution of the above equation and a solution corresponds to a partition in a 1-1 fashion.
Place the M-S+2 items along a line. To get a partition, consider placing n-1 sticks in the M-S+2-1 = M-S+1 spots available, between the items.
Thus a solution (and ultimately your required bit-pattern) uniquely corresponds to a way of choosing n-1 spots among M-S+1 spots.
In case of 5 bits, and 1 bits being 1 and 1.
You have n = 3, M = 5, and S = 2.
Thus you have M-S+1 choose n-1 = 4 choose 2 = 6 possiblities.
Enumerating n choose r combinations is a standard problem and you should find a large variety of solutions (some of them very clever!) for that on the web.
For an example see here: http://compprog.files.wordpress.com/2007/10/comb1.c which seems to support a 'lazy' enumeration: next_combination and does not require huge amounts of memory.
我不会向您提供 Objective-C 代码,主要是因为:
相反,我会给你一些想法和一些代码,展示如何使用生成器和垃圾收集(在本例中为 Python)以更高级的语言实现这一点,并提示如何在没有生成器的情况下实现这一点。如果您自己做不到,希望其他人能够为您移植代码。
我会以稍微不同的方式思考你的问题:
在上一个示例中,您有两个前导零和三个带有分隔符“10”和“1”的分区:
分隔符始终采用
111..10
形式,最后一个分隔符仅为111 ..1
没有尾随零。要枚举上述分区,请使用 Python 中如下所示的函数:
结果:
一旦有了这些分区,构建模式就很简单。
一项挑战是 Objective-C 没有对 Yield 构造的内置支持。对上述函数进行以下重写可能会更容易转换为 Objective-C:
我希望这对您有用。
I'm not going to give you Objective-C code mainly because:
Instead I will give you some ideas and some code showing how I would implement this in a higher language with generators and garbage collection (Python in this case) and a hint on how to do it without generators. Hopefully someone else may be able to port the code for you if you cannot do it yourself.
I would think about your problem in a slightly different way:
In your last example you have two leading zeros and three partitions with separators '10' and '1':
The separators are always of the form
111..10
except the last which is just111..1
without the trailing zero.To enumerate the above partitions use a function like the following in Python:
Result:
Once you have these partitions it is simple to construct the patterns.
One challenge is that Objective-C doesn't have built-in support for the yield construct. The following rewrite of the above function may be easier to convert to Objective-C:
I hope that is of some use to you.
基于 @Mark Byers 的 和 白痴的答案你的任务可以重新表述如下:枚举
将
K
个零放入N
个位置的所有方法(参见重复组合和星星和酒吧)。示例:对于 15 位和 1 2 6 1 模式,有 N=5 个位置(数字之前/之后以及
1
之间)放置 K=2 个零(同花顺的前导零的数量)正确的数字)。方式数是二项式(N + K - 1, K) 即二项式(5+ 2-1, 2) = 15.下面代码中的关键函数是
next_combination_counts()
和comb2number()
。C 输出中的完整程序
:
Building on @Mark Byers's and Moron's answers your task can be reformulated as follows:
Enumerate all ways to put
K
zeros intoN
places (see combinations with repetition and Stars and bars).Example: For 15 bits and 1 2 6 1 pattern there are N=5 places (before/after the number and between
1
s) to put K=2 zeros (number of leading zeros for a flush-right number). Number of ways is binomial(N + K - 1, K) i.e., binomial(5+2-1, 2) = 15.The key functions in the code below are
next_combination_counts()
andcomb2number()
.Full program in C
Output:
假设我们:
首先,计算 0 (
5
),并计算 1 包围的 0 组 (1
)。我们现在可以忘记 1。任何组合中每组零的数量可以是一个描述为的列表(其中+
表示“或更多”):这只是类似问题的变体:找到 N 个非负的所有集合总和为 K 的整数。例如:
现在,要解决此问题,请从 N=1 开始。解决方案显然就是
[6]
。当 N=2 时,解决方案是:重要的是要注意这里的潜在主题:随着左侧变得更富有,右侧变得更贫穷。我将使用 Haskell 来描述该算法,因为事实证明它对于此类事情非常优雅:
n == 1
情况非常容易理解:它只返回一个组合:<代码>[k]。在n>中1
情况,这里实际上发生了一个嵌套循环。它基本上是在说:虽然这个算法并不能完全解决你的问题,但总体上了解一下还是有好处的。
现在,我们希望算法以不同的方式运行,以处理中间列表项不能为零的情况。对于这些情况,我们希望使用
i <- [1..k]
而不是i <- [0..k]
。结束数字并不重要,因为它没有自由意志(它仅取决于前面项目的总和)。更接近的是,我们可能会说:但是,我们希望我们的第一个项目能够从零开始。为了修补这个问题,我们可以说:
给定
K
(0 的数量)和N
(内部 0 组的数量加上 2),这为我们提供了所需的序列)。剩下的就是对序列进行字符串化(例如将 [1,1,0] 转换为“01”)。我们甚至可以将字符串化直接嵌入到我们的递归算法中。总而言之,这是 Haskell 中的一个解决方案:
总之,我建议学习 Haskell,以便您可以更快地构建算法原型:-)
Suppose we have:
First, count the 0s (
5
), and count the groups of 0s surrounded by 1s (1
). We can forget about the 1s for now. The number of zeros per group in any combination can be a list described as (where+
means "or more"):This is just a variation of a similar problem: find all sets of N non-negative integers that sum to K. For example:
Now, to solve this, start with N=1. The solution is obviously just
[6]
. With N=2, the solution is:It's important to notice an underlying theme here: as the left side gets richer, the right side gets poorer. I'll use Haskell to describe the algorithm, as it turns out to be quite elegant for this type of thing:
The
n == 1
case is pretty easy to understand: it just returns one combination:[k]
. In then > 1
case, there's actually a nested loop going on here. It's basically saying:Although this algorithm doesn't quite solve your problem, it's good to know in general.
Now, we want the algorithm to operate differently to handle how the middle list items cannot be zero. For those cases, we want to use
i <- [1..k]
instead ofi <- [0..k]
. It doesn't matter for the end number since it has no free will (it depends solely on the sum of the previous items). Getting closer, we might say:However, we want our first item to be able to start at zero. To patch that up, we can say:
This gives us the sequences we need given
K
(the number of 0s) andN
(the number of inner groups of 0s plus 2). All that remains is stringifying the sequences (e.g. turning [1,1,0] into "01"). We could go as far as embedding the stringification directly into our recursive algorithm.Summing it all up, here is a solution in Haskell:
In conclusion, I recommend learning Haskell so you can prototype algorithms more quickly :-)
这是理论问题还是实践问题?您是否需要最优的 O(N) 或相当好的执行时间?如果这是一个实际问题,并且除非它在某些内容的内部循环中,否则只需检查每个 15 位数字就应该足够快了。只有 32k 个数字。
只需获取您的数字的分区,如下所示:
然后,对于每个 15 位数字,检查它是否生成与您的初始数字相同的组数组。
注意:groups 数组应该能够容纳最大数量的组(例如,15 位数字的大小应该为 8)。
Is this a theoretical or practical problem? Do you need the optimal O(N) or reasonably good execution time? If this is a practical problem, and unless it's in the inner loop of something, just checking every 15-bit number should be fast enough. It's only 32k numbers.
Just get the partitions for your number, something like this:
And then, for every 15-bit number, check if it produces the same groups array as your initial number.
Note: The groups array should be able to accommodate the maximum number of groups (e.g. should have size 8 for 15-bit numbers).
如果您的模式是
00101
(如示例所示),那么您可以考虑生成六个模式的一种方法是:查看模式
0000
,然后选择两个零来生成更改为 。现在您将得到类似于0011
的内容。现在只需在每个1
之后插入一个0
(最后一个除外)。现在您将拥有00101
。请注意,您正在从四个位置中选择两个,并且有六种不同的可能方法可以做到这一点(与您所写的一致)。现在您只需要一种方法来选择要翻转的两位。您可以使用类似于此链接中指定的算法:生成组合< /a>
If your pattern is
00101
, as in the example, then one way you can consider for generating the six patterns is:Look at the pattern
0000
then choose two of the zeroes to change to ones. Now you'll have something like0011
. Now just insert a0
after each1
(except for the last one). Now you'll have00101
.Note that you are choosing two out of four places, and there are six different possible ways you can do that (consistent with what you wrote). Now you just need a way to choose the two bits to flip. You can use something like the algorithm specified at this link: Generating Combinations