递增格雷码


36

介绍

甲格雷码是二进制表示的替代,其中许多是通过切换只有一个位,而不是比特的可变量的递增。以下是一些格雷码及其十进制和二进制等效项:

 decimal | binary | gray
-------------------------
       0 |      0 |    0
-------------------------
       1 |      1 |    1
-------------------------
       2 |     10 |   11
-------------------------
       3 |     11 |   10
-------------------------
       4 |    100 |  110
-------------------------
       5 |    101 |  111
-------------------------
       6 |    110 |  101
-------------------------
       7 |    111 |  100
-------------------------
       8 |   1000 | 1100
-------------------------
       9 |   1001 | 1101
-------------------------
      10 |   1010 | 1111
-------------------------
      11 |   1011 | 1110
-------------------------
      12 |   1100 | 1010
-------------------------
      13 |   1101 | 1011
-------------------------
      14 |   1110 | 1001
-------------------------
      15 |   1111 | 1000

格雷码的循环位模式

有时称为“反射二进制”,每次更改最低位的特性很容易实现:对于每列,从最低有效位开始,使用循环位模式:

bit 0: 0110011001100110011001100110011001100110011001100110011001100110
bit 1: 0011110000111100001111000011110000111100001111000011110000111100
bit 2: 0000111111110000000011111111000000001111111100000000111111110000
bit 3: 0000000011111111111111110000000000000000111111111111111100000000
bit 4: 0000000000000000111111111111111111111111111111110000000000000000
bit 5: 0000000000000000000000000000000011111111111111111111111111111111

...等等。

目的

给定一个未填充的格雷码输入字符串,请通过在序列中交替一个字符或在a前面加上1(当递增到下一个2的幂时)来递增格雷码,然后将结果作为未填充的格雷码输出。

注意事项

  • 不必担心采用0或输入空字符串。
  • 最低的输入为1,除了环境所施加的内存限制之外,字符串长度没有上限。
  • 所谓非填充字符串,是指0在输入或输出中将没有前导或尾随空格(除了可选的尾随换行符),并且也没有前导s。

I / O格式

可接受以下格式的输入和输出格式,但建议使用字符串作为其他格式:

  • 最重要的“位”在前
  • 非填充字符数组或ASCII串'1'S和'0'小号
  • 1s和0s的非填充整数数组
  • 非填充布尔数组

不允许的内容:

  • 最低有效“位”在前
  • 十进制,二进制或一元整数
  • 固定长度数据结构
  • 不可打印ASCII索引的字符数组或字符串,1以及0

测验

input -> output
1 -> 11
11 -> 10
111 -> 101
1011 -> 1001
1111 -> 1110
10111 -> 10110
101100 -> 100100
100000 -> 1100000

可以根据要求添加更多测试。

标准

这是,所以最短的程序以字节为单位!所有关系将因赞成较早提交而破裂。标准漏洞适用。最佳提交答案将在2016年10月9日被接受,并在给出更好答案时进行更新。



我们可以将输入作为数字吗?
— xnor

1
不太明显,也有关。
— Martin Ender

1
我可以将输入和输出都取反0011
— 吗

1
@TonHospel对不起,我没有看到您关于反向I / O的问题。正如我告诉10亿我的答案是否定的。
— 帕特里克·罗伯茨

Answers:


13

果冻,10 8字节

感谢Dennis节省了2个字节。

^\Ḅ‘^H$B

输入和输出是0和1的列表。

在线尝试!

说明

格雷码的反码由A006068给出。使用此方法,我们不需要生成大量的格雷码来查找输入。在OEIS上给出的该序列的一种分类是:

a(n) = n XOR [n/2] XOR [n/4] XOR [n/8] ...

哪里[]是地板支架。考虑44其二进制表示为的示例101100。除以2和下限只是一个右移,将最低有效位除掉。因此,我们正在尝试对以下数字进行异或运算

1 0 1 1 0 0
  1 0 1 1 0
    1 0 1 1
      1 0 1
        1 0
          1

请注意,第nth列包含前n几位。因此,该公式可以在二进制输入上进行微不足道的计算,作为列表上XOR的累计减少量(基本上将XOR应用于列表的每个前缀,并为我们提供结果列表)。

这为我们提供了一种转换格雷码的简单方法。然后,我们只增加结果并将其转换回格雷码。对于后面的步骤,我们使用以下定义:

a(n) = n XOR floor(n/2)

幸运的是,Jelly在对XOR进行XOR运算时似乎自动对其进行了下界。无论如何,这是代码:

^\          Cumulative reduce of XOR over the input.
  Ḅ         Convert binary list to integer.
   ‘        Increment.
    ^H$     XOR with half of itself.
       B    Convert integer to binary list.

您不需要Ḟ$; 按位运算符强制转换为int。
— 丹尼斯

@Dennis谢谢,我在写作时发现了这一点。:)
— Martin Ender

@MartinEnder是内部转换为大整数的整数吗?
— 帕特里克·罗伯茨

@PatrickRoberts是的,如果需要的话-它是Python的内幕。
— 乔纳森·艾伦

很好的分析和解释。
— 韦恩·康拉德

8

JavaScript(ES6),58个字节

s=>s.replace(s.split`1`.length%2?/.$/:/.?(?=10*$)/,c=>1-c)

直接切换适当的位。说明:如MartinEnder♦的答案所示,解码的格雷码中的每个位都是其自身及其左侧位的累积XOR或奇偶校验。然后,我们需要增加引起进位波纹的数量,该进位波纹将所有最右边的1位切换为0,然后将下一个0位切换为1。重新编码会导致代码中只有一个0位位置被切换。如果所有1位的奇偶校验为偶数,则最右边的位为0,因此我们仅切换最后一位。如果所有1位的奇偶校验为奇数,则最右边的位为1,我们需要找到最后一位。现在这是最后一位,因此我们需要切换的位是右下一位。


非常好的方法。是第一个?在/.?(?=10*$)/真正需要的?哦,没关系。是的。:-)
— Arnauld

8

Perl,27个 25字节

包括+1的 -p

在STDIN上输入输入字符串,例如

gray.pl <<< 1010

gray.pl:

#!/usr/bin/perl -p
s%(10*\K1(\K0)*)*%1-$&%e

Perl没有便宜的无限精度整数。因此,直接切换右位,即最后一个奇数1所在的位。


1
哇,\G真的很容易为您服务!
— 尼尔

1
另一方面,\K使您的工作变得更加轻松。
— 尼尔

Haaaaa ...现在我也想看看\G实现。
— 魔术章鱼缸

2
@carusocomputing您可以通过单击已编辑的链接来查看较早版本的提交内容
— Ton Hospel,2016年

6

Haskell,118115108字节

g 0=[""]
g n|a<-g$n-1=map('0':)a++map('1':)(reverse a)
d=dropWhile
f s=d(=='0')$(d(/='0':s)$g$1+length s)!!1

在Ideone上尝试。
原始的方法:g产生具有长度的集合中的所有格雷码的n(具有填充0),f调用g与length(input)+1,直至除去所有的元素0<inputstring>被发现,返回下一个元素(截断可能导致0)。


1
好的第一答案!我希望我们能尽快得到一些更高效的产品。
— 帕特里克·罗伯茨

5

MATL,18字节

ZBtE:t2/kZ~tb=fQ)B

在线尝试!或验证所有测试用例。

说明

让一个(Ñ)表示对应于格雷码(整数序列OEIS A003188)。该程序使用特征a(n)= n XOR floor(n / 2),其中XOR是按位的。

本质上,代码将输入转换为整数a 0,在序列中找到该整数,然后选择下一项。这需要生成足够大量的序列a(n)项。事实证明2· a 0足够大。这是因为格雷码a(n)的二进制数字永远不会比n多。

让我们以输入'101'为例。

ZB      % Input string implicitly. Convert from binary string to integer
        %   STACK: 5
t       % Duplicate
        %   STACK: 5, 5
E       % Multiply by 2. This is the number of terms we'll generate from the sequence
        %   STACK: 5, 10
:       % Range
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10]
t       % Duplicate
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10], [1 2 3 4 5 6 7 8 9 10]
2/k     % Divide by 2 and round down, element-wise
        %   STACK: 5, [1 2 3 4 5 6 7 8 9 10], [0 1 1 2 2 3 3 4 4 5]
Z~      % Bit-wise XOR, element-wise
        %   STACK: 5, [1 3 2 6 7 5 4 12 13 15]
t       % Duplicate
        %   STACK: 5, [1 3 2 6 7 5 4 12 13 15], [1 3 2 6 7 5 4 12 13 15]
b       % Bubble up
        %   STACK: [1 3 2 6 7 5 4 12 13 15], [1 3 2 6 7 5 4 12 13 15], 5
=       % Equality test, element-wise
        %   STACK: [1 3 2 6 7 5 4 12 13 15], [0 0 0 0 0 1 0 0 0 0]
f       % Find: yield (1-based) index of nonzero values (here there's only one)
        %   STACK: [1 3 2 6 7 5 4 12 13 15], 6
Q       % Increase by 1
        %   STACK: [1 3 2 6 7 5 4 12 13 15], 7
)       % Apply as index
        %   STACK: 4
B       % Convert to binary array
        %   STACK: [1 0 0]
        % Implicitly display

我注意到输出是用空格分隔的字符...它是否打印某种数组?
— 帕特里克·罗伯茨

@PatrickRoberts是的,完全是。我以为可以接受,是吗?
— Luis Mendo

我会原样接受。我已经放松了对I / O格式的要求,因此再严格一点也没有意义。不错的工作。
— 帕特里克·罗伯茨

5

CJam(19个字节)

{_2b__(^@1b1&*)^2b}

在线演示。这是一个从位数组到位数组的匿名块(函数),演示在循环中执行。

它的工作原理很简单:如果设置的位数是偶数,我们应该切换最低有效位,否则我们应该切换到最低有效设置位左侧的位。实际上,使用整数对位进行黑客攻击要比使用位列表要容易得多。

解剖

{         e# Declare a block:
  _2b     e#   Convert the bit array to a binary number
  __(^    e#   x ^ (x-1) gives 1s from the least significant set bit down
  @1b1&   e#   Get the parity of the number of set bits from the original array
  *       e#   Multiply: if we have an even number of set bits, we get 0;
          e#   otherwise we have 2**(lssb + 1) - 1
  )^      e#   Increment and xor by 1 or 2**(lssb + 1)
  2b      e#   Base convert back to a bit array
}

我认为仅使用位数组是有必要将其反转的:最左侧的操作1比最右侧的操作容易得多。到目前为止,我发现的最好的结果是(24个字节):

{W%_1b)1&1$+1#0a*1+.^W%}

替代方法(19字节)

{[{1$^}*]2b)_2/^2b}

这将从格雷码转换为索引,递增,然后转换回格雷码。


5

JavaScript(ES6),53个字节(非竞争)

一个递归函数,它将构建所有格雷码,直到找到输入为止,然后在下一次迭代时停止。

可能的最高输入取决于浏览器的递归限制(Firefox中约为13位,Chrome中约为15位)。

f=(s,n=1)=>(b=(n^n/2).toString(2),s)?f(b!=s&&s,n+1):b

console.log(f("1"));      // -> 11
console.log(f("11"));     // -> 10
console.log(f("111"));    // -> 101
console.log(f("1011"));   // -> 1001
console.log(f("1111"));   // -> 1110
console.log(f("10111"));  // -> 10110
console.log(f("101100")); // -> 100100
console.log(f("100000")); // -> 1100000


恐怕此提交不符合条件,因为该方法不适用于无限制的字符串长度。如果您想保留此答案,请更改为非竞争性。
— 帕特里克·罗伯茨

@PatrickRoberts-好的。那讲得通。
— 阿纳尔德

@PatrickRoberts真的吗?递归限制如何不属于“环境施加的内存限制”?
— 桑契斯,2013年

@sanchises我指的是堆内存,但更重要的是,该程序会针对所有可能的格雷码(直到要测试的代码)递归,这是非常低效的。从技术上讲,可以将其提交为“ Node.js 6.5”,并--harmony添加了惩罚字节以便访问尾调用递归优化,这在这里似乎是可能的。
— 帕特里克·罗伯茨

@sanchises看着我的答复,那是一个可怜的论点。主要问题是限制不是由环境强加的,而是由算法强加的。还有其他答案,每个答案而不是每个增量值都是递归的,我发现这些答案更容易接受,因为它适用于更大范围的值。
— 帕特里克·罗伯茨

2

视网膜,25字节

^(10*10*)*
$1:
1:
0
.?:
1

我认为应该有更好的方法来做...


您真的需要^吗?
— Ton Hospel '16

@TonHospel正则表达式试图在没有它的情况下与任何地方匹配。(替换模式默认为全局替换。)
— Neil

2

05AB1E,12个字节

使用CP-1252编码。

CÐ<^¹SOÉ*>^b

在线尝试!

说明

输入1011的示例。

C              # convert to int (bigint if necessary)
               # STACK: 11
 Ð             # triplicate
               # STACK: 11, 11, 11
  <            # decrease by 1
               # STACK: 11, 11, 10
   ^           # XOR
               # STACK: 11, 1
    ¹          # push first input
               # STACK: 11, 1, 1011
     S         # split to list
               # STACK: 11, 1, [1,0,1,1]
      O        # sum
               # STACK: 11, 1, 3
       É       # mod 2
               # STACK: 11, 1, 1
        *      # multiply
               # STACK: 11, 1
         >     # increase by 1
               # STACK: 11, 2
          ^    # XOR
               # STACK: 9
           b   # convert to binary
               # STACK: 1001
               # implicitly print top of stack

2

Python 2.7,68个字符

def f(s):i=long(s,2);print bin(i^(1,(i&-i)<<1)[s.count('1')&1])[2:]

Python 3,68个字符

def f(s):i=int(s,2);print(bin(i^(1,(i&-i)<<1)[s.count('1')&1])[2:])

此函数将给定的二进制字符串转换为整数,如果原始字符串中设置的位数为偶数,则将x转换为最后一位;如果原始字符串中设置的位数为零,则该函数将其交换到最右边设置位的左侧字符串是奇数。然后,它将结果转换为二进制字符串并删除0b布尔前缀。


1
您可以def f(s):通过使用print而不是来删除后面的空格(并假设Python 2)来节省1个字节return。
— ElPedro

@ElPedro谢谢,我也应用了条件技巧,并考虑了xor的左手尺寸以节省一些其他字符:)
— Morwenn

刚刚看到了。好答案:-)
— ElPedro '16

嗯..检查python文档,它看起来像int()生成一个32位整数,尽管我的要求是您要增加任何长度的字符串。我不确定这是否属于有效提交内容
— Patrick Roberts

1
@PatrickRoberts我待会再检查。long而不是int可能解决问题。
— Morwenn

2

C ++,205个字节

#include <string>
std::string g(std::string s){int i,z;if(s=="1")return"11";for(i=z=0;i<s.length();i++)if(s[i]=='1')z++;i--;if(z%2){char c=s[i];s.erase(i);s=g(s);s+=c;}else{s[i]=s[i]==49?48:49;}return s;}

描述:偶数等于偶数。可变z计数 如果z是偶数(z mod 2 = z%2 = 0-else分支),则更改最后一位;如果z是奇数,则在没有最后一个字符的情况下再次调用此函数并计算新值,然后再追加最后一个字符。

单击此处尝试测试用例。


感谢您的提交。如果您可以提供有关方法的简短描述以及作为演示的在线将此方法链接的链接,我将非常感谢。
— 帕特里克·罗伯茨

1
@PatrickRoberts根据您的要求添加了链接和说明。
— AlexRacer '16

2

批,199个 197字节

@echo off
set/ps=
set r=
set t=%s:0=%
if 1%t:11=%==1 goto g
:l
set b=%s:~-1%
set s=%s:~,-1%
set r=%b%%r%
if %b%==0 goto l
if 0%s%==0 set s=0
:g
set/ab=1-%s:~-1%
echo %s:~,-1%%b%%r%

从STDIN读取输入到变量s。删除0并对1进行奇偶校验,如果有奇数,它将在循环中剥离最右边的0,在剥离1时停止,s因此包含偶数奇偶校验前缀和r其余字符串。s如果为空,则将其设置为零,以便可以切换其最后一位,然后将所有内容串联在一起。


1

实际上是20 19 13个字节

基于马丁·恩德(Martin Ender)的Jelly答案,以及我自己的版本“对输入进行XOR的累积减少”。欢迎打高尔夫球。在线尝试!

σ1♀&2@¿u;½≈^├

开球

      Implicit input a as a list, such as [1,0,1,1,0,0].
σ     Get the cumulative sums of a.
1♀&   Map x&1 (equivalent to x%2) over every member of the cumulative sum.
2@¿   Convert from binary to decimal.
u     Increment x.
;½≈   Duplicate and integer divide by 2.
^     XOR x and x//2.
├     Convert to binary to obtain our incremented Gray code.
      Implicit return as a string, such as "100100".

1

J,38个字节

[:#:@(22 b.<.@-:)@>:@#.[:22 b./[:#:#.\

在线尝试!

这本质上是J中的马丁算法。

请注意,这22 b.是XOR。

                                    [: #: #.\   Creates the prefixes of the input
                                                converts to a number, then converts
                                                back to binary.  Needed to get the
                                                padding on the left.

                          [: 22 b./             Reduce the rows of the resulting 
                                                matrix with XOR, giving us the 
                                                normal binary
                      @#.                       Convert to int and...
                   @>:                          Increment and...
      (22 b. <.@-:)                             XOR that with its own floored half
[: #:@                                          And turn the result back to binary

干得好,伙计!
— 帕特里克·罗伯茨
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.