【问题标题】:Creating a custom binary pattern from a given number从给定数字创建自定义二进制模式
【发布时间】:2020-12-05 16:53:27
【问题描述】:

给定 n,我有一个二进制模式要在我的应用程序的一部分中生成,如下所示:

n = 0

0 -> 0

n = 1

0 -> 0
1 -> 1

n = 2

0 -> 00
1 -> 01
2 -> 10
3 -> 11

n = 3

0 -> 000
1 -> 001
2 -> 010
3 -> 100
4 -> 011
5 -> 101
6 -> 110
7 -> 111

n = 4

0 -> 0000
1 -> 0001
2 -> 0010
3 -> 0100
4 -> 1000
5 -> 0011
6 -> 0101
7 -> 1001
8 -> 0110
9 -> 1010
10 -> 1100
11 -> 0111
12 -> 1011
13 -> 1101
14 -> 1110
15 -> 1111

n = 5

0 -> 00000
1 -> 00001
2 -> 00010
3 -> 00100
4 -> 01000
5 -> 10000
6 -> 00011
7 -> 00101
8 -> 01001
9 -> 10001
10 -> 00110
11 -> 01010
12 -> 10010
13 -> 01100
14 -> 10100
15 -> 11000
16 -> 00111
17 -> 01011
18 -> 10011
19 -> 01101
20 -> 10101
21 -> 11001
22 -> 01110
23 -> 10110
24 -> 11010
25 -> 11100
26 -> 01111
27 -> 10111
28 -> 11011
29 -> 11101
30 -> 11110
31 -> 11111

我会尽力解释这个算法:

算法有循环。在每个循环中,都会翻转一个额外的位。然后组合出来。

所以在第一个循环中,没有位是 1。

在第二个循环中,只有一位是 1。我们需要首先遍历所有可能的组合,这样的顺序是只有在最右边位的所有组合都结束后,最左边的位才会点亮。

类似地继续进行进一步的循环。

我不确定如何为它编写高效的代码。我能想到的一件事就是这个问题的 DP 解决方案。但是有没有更优雅的,比如数学解决方案,我可以在其中输入“n”并获得等效的二进制模式?

【问题讨论】:

  • 你可以使用the famous algorithm of listing integers with the same Hamming weight,并为每一个可能的体重这样做
  • 关于“我们需要首先检查所有可能的组合,按照这样的顺序,只有在最右边位的所有组合都结束后,最左边的位才会点亮”:这不是您的示例所显示的;对于 n=4,它具有“7 -> 1001”,后跟“8 -> 0110”。哪个是正确的?
  • 请澄清有关订单的陈述与示例之间的差异。其中一个是错误的。

标签: algorithm math binary


【解决方案1】:

您可以使用递归方法。在主例程中,增加您想要生成的一位数(从 1 到 n),然后调用一个递归函数来完成这项工作,如下所示:

它选择一个位设置为1,然后递归调用该函数以使用它右边的剩余位,以减少一位。

这是一个 JavaScript 实现,带有 n=4 的演示运行:

function * generateOnes(numDigits, numOnes) {
    if (numDigits === 0 || numOnes === 0) {
        yield 0;
    } else {
        for (let pos = numOnes - 1; pos < numDigits; pos++) {
            for (let result of generateOnes(pos, numOnes - 1)) {
                yield (1 << pos) | result;
            }            
        }
    }
}

function * generate(numDigits) {
    for (let numOnes = 1; numOnes <= numDigits; numOnes++) {
        yield * generateOnes(numDigits, numOnes);
    }
}

// Demo with n=4:
for (let result of generate(4)) {
    console.log(result.toString(2).padStart(4, "0"));
}

这是 Python 中的等价物:

def generate_ones(num_digits, num_ones):
    if num_digits == 0 or num_ones == 0:
        yield 0
    else:
        for pos in range(num_ones - 1, num_digits):
            for result in generate_ones(pos, num_ones - 1):
                yield (1 << pos) | result

def generate(num_digits):
    for num_ones in range(1, num_digits + 1):
        yield from generate_ones(num_digits, num_ones)

# Demo with n=4:
for result in generate(4):
    print('{0:04b}'.format(result))

【讨论】:

  • 非常感谢!您是否看到了一种优化方法,如果给定 n 和一个数字,它可以生成等效的二进制模式,而不必生成整个事物?例如,n = 5 和 number = 10,那么二进制等效模式 = 00110。
  • 我没有看到它的封闭公式。我认为对于这类问题,您可以从math.stackexchange.com 社区获得更好的意见,因为它不再与编程有关。当然,如果n不是太大,你可以一次生成整个列表,存储,然后从中挑选。
【解决方案2】:
n=int(input())
a=[]
for i in range(2**n):
    Str = bin(i).replace('0b','')
    a.append(Str)
for i in range(len(a)):
    a[i] = '0'*(n-len(a[i])) + a[i]
for i in range(len(a)):
    print(a[i])

如果您对代码注释有任何疑问

【讨论】:

  • 感谢您的回答。但是这个答案打印出十进制数的二进制等价物。我的情况有点不同。请查看示例输入输出。
  • 如果您必须根据我从上面的示例中感知到的模式生成模式,那么您可以将打印语句修改为print(i," -&gt; ",a[i])
  • 例如,您上面给出的代码输出中的第 4 个条目是 00011,但在我的示例中,它将是 01000
  • 对不起!我误解了你的问题。会再试一次
【解决方案3】:

假设“我们需要首先检查所有可能的组合,按照这样的顺序,只有在最右边位的所有组合都结束后,最左边的位才会点亮”是正确的,并且为 n显示的示例>=4:

7 -> 1001
8 -> 0110

错了,那么这里是 C 代码,可以根据需要遍历值:

#include <stdio.h>


//  Print the n-bit binary numeral for x.
static void PrintBinary(int n, unsigned x)
{
    putchar('\t');

    //  Iterate through bit positions from high to low.
    for (int p = n-1; 0 <= p; --p)
        putchar('0' + ((x >> p) & 1));

    putchar('\n');
}


/*  This is from Hacker’s Delight by Henry S. Warren, Jr., 2003,
    Addison-Wesley, Chapter 2 (“Basics”), Section 2-1 “Manipulating Rightmost
    Bits”, page 14.
*/
static unsigned snoob(unsigned x)
{
    /*  Consider some bits in x dddd011...1100...00, where d is “do not care”
        and there are t bits in that trailing group of 1s.  Then, in the code
        below:

            smallest is set to the trailing 1 bit.

            ripple adds to that bit, carrying to the next 0, producing
            dddd100...0000...00.  Note that t 1 bits changed to 0s and one 0
            changed to 1, so ripple has t-1 fewer 1 bits than x does.

            ones is set to all bits that changed, dddd111...1100...0.  It has
            t+1 bits set -- for the t 1s that changed to 0s and the 0 that
            changed to 1.

            ones/smallest aligns those bits to the right, leaving the lowest
            t+1 bits set.  Shifting right two bits leaves t-1 bits set.

            Then ripple | ones restores t-1 1 bits in the low positions,
            resulting in t bits set.
    */
    unsigned smallest = x & -x;        // Find trailing 1 bit.
    unsigned ripple   = x + smallest;  // Change it, carrying to next 0.
    unsigned ones     = x ^ ripple;    // Find all bits that changed.
    ones = ones/smallest >> 2;
    return ripple | ones;
}


/*  Give a number of bits n, iterate through all values of n bits in order
    first by the number of bits set then by the binary value.
*/
static void Iterate(int n)
{
    printf("Patterns for n = %d:\n", n);

    //  Iterate s through the numbers of bits set.
    for (int s = 0; s <= n; ++s)
    {
        /*  Set s low bits.  Note:  If n can equal (or exceed) the number of
            bits in unsigned, "1u << s" is not defined by the C standard, and
            some alternative must be used.
        */
        unsigned i = (1u << s) - 1;

        //  Find the highest value.
        unsigned h = i << n-s;

        PrintBinary(n, i);
        while (i < h)
        {
            i = snoob(i);
            PrintBinary(n, i);
        }
    }
}


int main(void)
{
    for (int n = 1; n <= 4; ++n)
        Iterate(n);
}

【讨论】:

  • 谢谢!有没有办法不必遍历整个事物并获得给定数字和给定'n'的等效模式?例如,n = 5 和 number = 10,那么二进制等效模式 = 00110。
猜你喜欢
  • 1970-01-01
  • 2023-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-11
  • 1970-01-01
  • 2014-05-24
  • 2014-06-28
相关资源
最近更新 更多