生成圣殿天际线序列


39

请考虑以下过程:

  1. 取一些非负整数N。

    例如N = 571

  2. 以二进制形式表示,没有前导零。(零本身是唯一的例外,成为0。)

    例如571= 1000111011二进制

  3. 在此二进制表示中,将连续的1和0分开。

    例如10001110111000111011

  4. 从最长到最短对运行进行排序。

    例如10001110110001111110

  5. 用交替1的和替换每次运行中的所有数字0,始终以开头1

    例如00011111101110001101

  6. 连接结果以获得新的二进制数。

    例如11100011011110001101= 909十进制

当您绘制由此过程产生的值时,会得到一个漂亮的图形:

庙宇天际线图至1024

希望我将为什么将所得序列称为Temple Skyline序列是显而易见的:

庙宇天际线

挑战

编写一个使用非负整数N并打印或返回相应的Temple Skyline序列号的程序或函数。您的输入和输出都应为十进制。

例如,如果输入为571输出,则应为909

以字节为单位的最短代码获胜。

作为参考,以下是从N = 0到20的顺序中的术语:

0   1
1   1
2   2
3   3
4   6
5   5
6   6
7   7
8   14
9   13
10  10
11  13
12  12
13  13
14  14
15  15
16  30
17  29
18  26
19  25
20  26

以下是0到1023之间的术语。

Answers:


4

Pyth,20个 19字节

ACr.BQ8|is*V_SGH2 1

Jakube保存了1个字节

测试套件

使用以下事实:在运行长度编码之后,运行是输出中所需的运行。

丢失3个字节的特殊大小写0。


14

CJam,25 23 22字节

ri1e>2be`z($W%a\+ze~2b

只是游程长度编码。-1感谢@MartinBüttner。

在线试用 / 测试套件

说明

ri        Read n from input as int
1e>       Take max with 1 (special case for n = 0)
2b        Convert n to binary
e`        Run length encode
z         Zip, giving a pair [<counts> <10101.. array>]
($W%      Drop the counts array and sort decending
a\+z      Add it back to the 10101.. array and re-zip
e~        Run length decode
2b        Convert from binary

11

Pyth- 21 20字节

感谢@sok为我节省了一个字节!

is.em%hk2hb_Sr.BQ8 2

在这里在线尝试


您可以使用.BQ替代的jQ2,这意味着你可以失去之间的空间8和前面2
2015年

is*R`s=!Z_ShMr.BQ8 2是一个有趣的等长解决方案。主要是发布,因为我并不真正希望map参数中的assign起作用。
FryAmTheEggman 2015年

1
@FryAmTheEggman替换`s]。保存一个字节。
雅库布2015年

6

Python 2,121字节125

121:感谢Sp3000削减了4个字节!

import re;print int("".join(n*`~i%2`for i,n in enumerate(sorted(map(len,re.split('(1*|0+)',bin(input())[2:])))[::-1])),2)

125

import re;print int("".join("10"[i%2]*n for i,n in enumerate(sorted(map(len,re.split('(1*|0+)',bin(input())[2:])))[::-1])),2)

1
真好!我相信您也可以n*`~i%2`for代替"10"[i%2]*n for
Sp3000 2015年

感谢您的编辑!我不得不迅速着手,但想提交,因为我认为这是一个美丽的挑战,对于第一次提交是一个很好的挑战。我将尽快检查您的提交!
enpenax 2015年

我认为您可以通过使用sorted(...,key=len)而不是使用来节省一些字节,map(len,...但是我现在还不完全了解您的程序,因此我不认为这会对您有所帮助。
科尔

嗨,@ Cole我正在映射,len因为这是我需要复制1和0数量的唯一信息。我尝试了您的建议,它增加了2个字节,因为len那时我将不得不使用两次,但是感谢您的建议!
enpenax

5

的JavaScript ES6,110字节113 116 119 120

@intrepidcoder节省了3个字节

@NinjaBearMonkey节省了3个字节

n=>+('0b'+n.toString(2).split(/(0+)/).sort((b,a)=>a.length-b.length).map((l,i)=>l.replace(/./g,i-1&1)).join``)

直截了当的方法。不喜欢排序功能的长度,但我想不出一种打高尔夫球的方法。


我认为您可以使用+而不是eval
intrepidcoder

@intrepidcoder谢谢,那节省了3个字节!
Downgoat

我无法测试,但split(/(0+)/g)应该可以替换match(/(.)\1*/g)
NinjaBearMonkey 2015年

@NinjaBearMonkey谢谢,那节省了3个字节!
2015年

保存一个字节: +(s=0, ... .map(l=>l.replace(/./g,s^=1))...)
希望我能帮忙

5

C ++,535个 527字节

(感谢zereges削减了一些字节。)

现在我们已经摆脱了这些字节,该程序现在具有竞争力;)

#include<iostream>
#include<cmath>
int main(){int I,D;std::cin>>I;while(I>int(pow(2,D))){D++;}int L[99];int X=0;int Z=0;int O=0;for(int i=D-1;i>=0;i--){if( int(pow(2,i))&I){if(Z>0){L[X]=Z;Z=0; X++;}O++;}else{if(O>0){L[X] = O;O=0;X++;}Z++;}}if(Z>0){L[X]=Z;Z=0;X++;}if(O>0){L[X]=O;O=0;X++;}int P=0;bool B = true;int W = D-1;for(int j=0;j<X;j++){int K=0;int mX=0;for(int i=0;i<X;i++){if(L[i]>K){K=L[i];mX=i;}}L[mX]=0;if(B){for(int k=0;k<K;k++){P+=int(pow(2,W));W--;}}else{for(int k=0;k<K;k++){W--;}}B^=1;}std::cout<<P;return 0;}

我是打高尔夫球的新手,所以请在评论中给我一些提示

诸如“您不需要那些括号”或“使用printf”之类的东西都很有帮助,但是我也很感谢有关逻辑的建议。提前致谢!

为了便于阅读,我提出了非高尔夫版本:

#include<iostream>
#include<cmath>
int main()
{
int input,digits;

std::cin>>input;
while(input > int(pow(2,digits))){digits++;}

int list[99];
int index=0;
int zCounter=0;
int oCounter=0;

for(int i=digits;i>0;i--)
{
    if( int(pow(2,i-1))&input)
    {
        if(zCounter>0)
        {
            list[index] = zCounter;
            zCounter=0;
            index++;
        }
        oCounter++;
    }
    else
    {
        if(oCounter>0)
        {
            list[index] = oCounter;
            oCounter=0;
            index++;
        }
        zCounter++;
    }
}
if(zCounter>0)
{
        list[index] = zCounter;
        zCounter=0;
        index++;
}
if(oCounter>0)
{
        list[index] = oCounter;
        oCounter=0;
        index++;
}

int output = 0;
bool ones = true;
int power = digits-1;
for(int j=0;j<index;j++)
{
    int max=0;
    int mIndex=0;
    for(int i=0;i<index;i++)
    {
        if(list[i]>max){max=list[i];mIndex=i;}
    }
    list[mIndex]=0;

    if(ones)
    {
        for(int k=0;k<max;k++)
        {
            output+=int(pow(2,power));
            power--;
        }
    }
    else
    {
        for(int k=0;k<max;k++)
        {
            power--;
        }
    }
    ones^=1;

}
std::cout<<output;
return 0;
}

编辑高尔夫版本降低了几个字节,未高尔夫版本保持不变


您可以代替int a; int b;使用int a,b;。全局范围内的变量也用初始化0。同样,当只有一个命令要执行时,您不必使用大括号。也ones=!ones;可以简化为ones ^= 1;
Zereges

保存了一些字节,谢谢
Liam 2015年

将第一个for循环移动1,即,for(int i=D;i;i--)然后pow(2,i-1)在循环内使用。
nimi 2015年

@LiamNoronha您实际上没有保存我推荐的内容:)
Zereges 2015年

1
@LiamNoronha 看看这个。仍有很大的改进空间。例如,重用变量(保存定义)ones也可以是int。也许宏int(pow(i))P(i)。我建议您在这里
Zereges 2015年

2

Haskell中,132个 131字节

import Data.List
g 0=[]
g n=mod n 2:g(div n 2)
q=[1]:[0]:q
f=foldl((+).(2*))0.concat.zipWith(<*)q.sortOn((-)0.length).group.g.max 1

用法示例:

> map f [0..20]
[1,1,2,3,6,5,6,7,14,13,10,13,12,13,14,15,30,29,26,25,26]

这个怎么运作:

                 max 1         -- fix n=0: f(0) is the same as f(1)
               g               -- turn into binary, i.e. list of 0s and 1s
            group              -- group sequences of equal elements
         sortOn((-)0.length)   -- sort groups on negative length
      zipWith(<*)q             -- map each element in a group to constant 1 or 0 by turns
   concat                      -- flatten all groups into a single list
foldl((+).(2*))0               -- convert back to decimal

2

J-30个字节

函数在右边取整数。正确处理0。

(\:~#2|#\)@(#;.1~1,2~:/\])&.#:
  • #: -以二进制表示。
  • 1,2~:/\]-在每个数字之间,如果它们不同,则报告True。在True前面添加一个True,以便在每个“运行”开始时列表中都具有True
  • (#;.1~...) -使用上述布尔向量,计算每次运行的长度。
  • \:~ -将这些长度从最长到最短排序。
  • 2|#\-取1 0 1 0 ...长短交替的列表。
  • (...#...) -对于左侧的每个数字(长度排序),在右侧获取尽可能多的相应项目(1和0交替显示)
  • &. -将此新的二进制表示形式转换回数字。

例子:

   (\:~#2|#\)@(#;.1~1,2~:/\])&.#: 571
909
   i.21   NB. zero to twenty
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   (\:~#2|#\)@(#;.1~1,2~:/\])&.#: every i.21   NB. apply separately to every number
1 1 2 3 6 5 6 7 14 13 10 13 12 13 14 15 30 29 26 25 26

2

Perl 5.10的,121 101

say oct"0b".join'',map{$|=1-$|;$_=~s/./$|/gr}sort{length$b<=>length$a}(sprintf"%b",shift)=~/(0*|1*)/g

我认为排序部分可以缩短。

编辑:-20个字节,感谢symbabque!


您可以摆脱\n,而m正则表达式匹配不需要。在替代中,只需使用.而不是char组。
simbabque 2015年

也不需要该grep部分。虽然oct很整洁:)
simbabque 2015年

谢谢,我无意中从原始代码中删除了这些部分。
LaposhasúACSA

1

Python 3中,146个 136字节

import re;print(int(''.join(len(j)*'01'[i%2<1]for i,j in enumerate(sorted(re.findall('1+|0+',bin(int(input()))[2:]),key=len)[::-1])),2))

而不是map使用a lambda,会更好''.join(... for ... in ...)吗?
Sp3000 2015年

1

Mathematica,83个字节

Flatten[0#+(d=1-d)&/@SortBy[d=0;Split[#~IntegerDigits~2],-Length@#&]]~FromDigits~2&

这定义了一个未命名的函数。


0

红宝石,107个 104 102字节

(由于nimi节省了3个字节)

不会击败CJam之类的人,但是对于一门理智的语言来说,它却很小。

p gets.to_i.to_s(2).scan(/((.)\2*)/).map{|e|e[i=0].size}.sort.reverse.map{|e|"#{i=1-i}"*e}.join.to_i 2

要保存的几个字节(i+=1)%2i=1-i
nimi 2015年

@nimi啊,谢谢。我试图弄清楚如何缩短它。
恢复莫妮卡iamnotmaynard,2015年

0

Java的8,179个 176字节

(x)->{int g[]=new int[32],h=0,i=highestOneBit(x);g[0]=1;while(i>1)g[((x&i)>0)^((x&(i>>=1))>0)?++h:h]++;sort(g);for(i=32,h=0;g[--i]>0;)while(g[i]-->0)h=h<<1|i%2;return x<1?1:h;}

我使用了两个静态导入:java.util.Integer.highestOneBitjava.util.Arrays.sort

为了提高可读性,下面是不包含代码的代码:

java.util.function.ToIntFunction<Integer> f = (x) -> {
  int g[] = new int[32], h = 0, i = java.util.Integer.highestOneBit(x);
  g[0] = 1;
  while (i > 1) {
    g[((x & i) > 0) ^ ((x & (i >>= 1)) > 0) ? ++h : h]++;
  }
  java.util.Arrays.sort(g);
  for (i = 32, h = 0; g[--i] > 0;) {
    while (g[i]-- > 0) {
      h = h << 1 | i % 2;
    }
  }
  return x < 1 ? 1 : h; // handle zero
};

-1

Python 2,170个字节

def t(n):
  from itertools import groupby;lst=sorted([''.join(g) for n,g in groupby(bin(n)[2:])],key=len)[::-1];s=''
  for i in lst:s+=str(i)
  return int(s,2)

4
欢迎来到PPCG!不幸的是,我认为这为某些数字给出了错误的值,例如t(0) = 01预期时间和预期t(4) = 1时间6
Sp3000
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.