De 0 a 2 ^ n - 1 en orden POPCORN

18

... Ah lo siento, no hay palomitas de maíz aquí, solo POPCNT.

Escriba el programa o la función más corta que tome un número ny genere todos los enteros de 0 a 2 n - 1, en orden ascendente de número de 1 bits en la representación binaria de los números (popcount). No se permiten duplicados.

El orden de los números con el mismo popcount está definido por la implementación.

Por ejemplo, para n = 3, todos estos resultados son válidos:

0, 1, 2, 4, 3, 5, 6, 7
[0, 4, 1, 2, 5, 3, 6, 7]
0 4 2 1 6 5 3 7 

El formato de entrada y salida está definido por la implementación para permitir el uso de funciones de lenguaje para mejorar el código. Hay algunas restricciones en la salida:

  • Los números deben salir en formato decimal.
  • La salida debe contener un separador razonable entre los números (separador final permitido, pero no inicial).

    Avance de línea ( \n), pestaña ( \t), espacio, ,, ., ;, |, -, _, /son separador bastante razonable. No me importan espacios adicionales para una impresión bonita, pero no use letras o dígitos como separadores.

  • Los números y separadores pueden estar rodeados por [ ], { }o cualquier matriz o notación de lista.
  • No imprima nada más no mencionado anteriormente.

Prima

Multiplique su puntaje por 0.5 si su solución puede generar el número sobre la marcha. El espíritu de este bono es que si fuera a convertir directamente su solución de impresión en un generador, el generador solo usa como máximo la memoria O (n) donde n es el número de bits como se definió anteriormente. (No tiene que convertir su solución en generador). Tenga en cuenta que si bien impongo n <= 28, la memoria necesaria para almacenar todos los números aún crece exponencialmente, y una solución de clasificación ingenua acumularía al menos 4 GB de memoria en n = 28.

Agregue alguna explicación simple de cómo funciona su solución antes de reclamar este bono.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
fuente
44
Parece que el desafío es bastante aburrido y daría lugar a un montón de respuestas de clasificación. Me gustaría agregar algo de bonificación para hacer que el desafío sea más interesante. Algo en la línea de "generar los números sobre la marcha". Si está de acuerdo con esto, vote por favor este comentario, luego lo agregaré a la pregunta.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Si no está de acuerdo, vote por favor este comentario.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Utilice el sandbox para solicitar más sugerencias sobre una pregunta antes de publicarla en vivo.
John Dvorak
21
@ JanDvorak: Estuvo en sandbox durante un mes.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
1
Creo que es demasiado tarde para esta pregunta. En general, en mi opinión, las preguntas en las que tienes que descubrir un algoritmo no trivial no son adecuadas para el golf de código. Conviértalos en un desafío de código y plantee todas las restricciones que necesita.
FUZxxl

Respuestas:

10

Pyth, 9 bytes

osjN2U^2Q

order por el sum de la representación de base 2 ( jN2) sobre el rango ( U) de 2 ^ Q.

( Q= eval(input()))

Pruébalo aquí

isaacg
fuente
7

Python 2, 75 * 0.5 = 37.5

N=2**input()-1
v=N-~N
while v:t=1+(v|~-v);v=N&t|~-(t&-t)/(v&-v)/2;print v^N

Repetidamente genera el siguiente más alto vcon el mismo POPCOUNT por este algoritmo de giro de bits .

En realidad, resultó más fácil generarlos disminuyendo el conteo de pops, luego imprimió el complemento para aumentarlo. De esa forma, luego se vdesborda 2**n, simplemente eliminamos todos los nbits, excepto &Ndonde N=2**n-1, y eso le da al popcount número uno más pequeño más bajo. De esa manera, solo podemos hacer un bucle. Probablemente haya una mejor solución que encuentre directamente el siguiente número más bajo con el mismo POPCOUNT.

Debido a un problema de poste de la cerca, necesitamos comenzar v=2**(n+1)-1para que la operación produzca v=N-1en el primer bucle.

Salida para 4:

0
8
4
2
1
12
10
9
6
5
3
14
13
11
7
15
xnor
fuente
No es necesario que aumente el número con el mismo popcount. El orden está definido por la implementación.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
1
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Soy consciente, pero no veo cómo salvar a los personajes de manera diferente.
xnor
Con un ingenuo método de 3 bucles, obtengo casi el mismo puntaje en JS (que tiene console.log()vs print). Tal vez el truco es demasiado pesado.
edc65
Ahorro de un byte:v=N-~N
Sp3000
5

J, 19 caracteres, sin bonificación.

[:(/:+/"1@#:)@i.2^]
  • 2 ^ y- dos al poder de y.
  • i. 2 ^ y- los enteros de 0a (2 ^ y) - 1.
  • #: i. 2 ^ y - cada uno de estos enteros representados en la base dos.
  • +/"1 #: i. 2 ^ y - las sumas de cada representación
  • (i. 2 ^ y) /: +/"1 #: i. 2 ^ y- el vector i. 2 ^ yordenado por el orden de los elementos del vector anterior, nuestra respuesta.
FUZxxl
fuente
3

Python, 63 caracteres

F=lambda n:`sorted(range(1<<n),key=lambda x:bin(x).count('1'))`

>>> F(3)
'[0, 1, 2, 4, 3, 5, 6, 7]'
Keith Randall
fuente
@Alex: la lista de restricciones implicaba que quería un resultado de cadena.
Keith Randall
Lo siento, me perdí eso.
Alex A.
3

C 179 * 0.5 = 89.5

main(){int n,i=0,m,o;scanf("%d",&n);m=~((~0)<<n);for(;n--;++i){for(o=0;o<m;++o){int bc=0,cb=28;for(;cb--;)bc+=o&(1<<cb)?1:0;if(bc==i)printf("%d ",o);}}printf("%d\n",m);return 0;}

EDITAR: 157 * 0.5 = 78.5

main(){int n,i=0,m,o;scanf("%d",&n);m=~((~0)<<n);for(++n;n--;++i){for(o=0;o<=m;++o){int bc=0,cb=28;for(;cb--;)bc+=o&(1<<cb)?1:0;if(bc==i)printf("%d ",o);}}}

EDITAR: 132 * 0.5 = 66

main(){int n,i=0,m,o;scanf("%d",&n);m=~((~0)<<n);for(++n;n--;++i){for(o=0;o<=m;++o){if(__builtin_popcount(o)==i)printf("%d ",o);}}}

o un poco mejor formateado:

main()
{
    int n, i = 0, m, o;
    scanf("%d", &n);
    m = ~((~0) << n);
    for(++n; n--; ++i)
    {
        for(o = 0; o <= m; ++o)
        {
            if (__builtin_popcount(o) == i)
                printf("%d ", o);
        }
    }
}

¿Que hace?

m = ~((~0) << n);

calcula el último número para mostrar (pow (2, n) - 1)

    for(++n; n--; ++i)
    {
        for(o = 0; o <= m; ++o)
        {

el bucle externo itera sobre el recuento de bits (de 0 a n-1) mientras que el bucle interno solo cuenta de 0 a m

            if (__builtin_popcount(o) == i)
                printf("%d ", o);

En x86 existe la instrucción POPCNT que se puede usar para contar los bits establecidos. GCC y los compiladores compatibles pueden admitir la función __builtin_popcount que básicamente compila esa instrucción.

Felix Bytow
fuente
2

CJam, 13 bytes

2ri#,{2b1b}$p

Implementación bastante sencilla.

Cómo funciona :

2ri#,             "Get an array of 0 to 2^n - 1 integers, where n is the input";
     {    }$      "Sort by";
      2b1b        "Convert the number to binary, sum the digits";
            p     "Print the array";

Pruébalo en línea aquí

Optimizador
fuente
2

Mathematica, 50 46

SortBy[Range[0,2^#-1],Tr@IntegerDigits[#,2]&]&

.

SortBy[Range[0,2^#-1],Tr@IntegerDigits[#,2]&]&

{0, 1, 2, 4, 8, 16, 3, 5, 6, 9, 10, 12, 17, 18, 20, 
24, 7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 15, 
23, 27, 29, 30, 31}
Savenkov Alexey
fuente
@ MartinBüttner, fijo! ¡¡¡Gracias!!!
Savenkov Alexey
1

JavaScript (ES6) 41 (82 * 0.5)

La forma más simple, golf

F=b=>{
  for(l=0;l<=b;l++)
    for(i=1<<b;i;t||console.log(i))
      for(t=l,u=--i;u;--t)
        u&=u-1;
}

Sin golf

F=b=>
{
  for (l = 0; l <= b; l++)
  {
    for (i = 1 << b; i > 0; )
    {
      --i;
      for (t = 0, u = i; u; ++t) // Counting bits set, Brian Kernighan's way
        u &= u - 1;
      if (t == l) console.log(i);
    }
  }
}

Prueba en la consola Firefox / FireBug

F(4)

0
8
4
2
1
12
10
9
6
5
3
14
13
11
7
15

edc65
fuente
1

Bash + coreutils, 66

Uno para comenzar:

jot -w2o%dpc $[2**$1] 0|dc|tr -d 0|nl -ba -v0 -w9|sort -k2|cut -f1
Trauma digital
fuente
Nada realmente emocionante aquí. Dado su comentario , felizmente eliminaré / revisaré esta respuesta si desea cambiar la pregunta.
Trauma digital
No estoy seguro de si debo resaltar que su programa debe funcionar para todos los valores de n desde 0 hasta 28 inclusive. No sé cuántas respuestas aquí pasan ese requisito.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
He eliminado la cláusula, ya que la gente no parece darse cuenta de todos modos.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Ahora, en teoría, al menos debería funcionar hasta 28. He probado hasta 22 hasta ahora, pero, por supuesto, esto sortlleva mucho tiempo. Con n = 28, sortnecesitará ordenar 2 ^ 28 líneas / ~ 13GB de datos.
Trauma digital
1

Haskell, (87 * 0.5) = 43,5

f n=[0..n]>>=(\x->x#(n-x))
a#0=[2^a-1]
0#_=[0]
a#b=[1+2*x|x<-(a-1)#b]++[2*x|x<-a#(b-1)]

Ejemplo de uso: f 4que genera[0,1,2,4,8,3,5,9,6,10,12,7,11,13,14,15]

Cómo funciona: sin ordenar ni iterar repetidamente sobre [0..2 ^ n-1] y buscar números que contengan i 1s.

Las #funciones auxiliares toman dos parámetros ay bconstruyen una lista de cada número compuesto por a1s y b0s. La función principal frequiere #cada combinación de ay bdonde a+bes igualn , comenzando sin nnúmeros 1 y 0 para tener los números en orden. Gracias a la pereza de Haskell, todas esas listas no tienen que construirse completamente en la memoria.

nimi
fuente
No el ++de a#bmedia que necesita el lado izquierdo (que podría ser grande) que se produce por completo y luego se copia antes de que se produjo el primer elemento en el resultado, violando de esta manera los requisitos para la bonificación?
Jules
Ah, no, pensar en ello todavía puede generarlos de manera perezosa mientras se producen, solo necesita hacer una copia de cada elemento, ya que ambos pueden recolectarse basura durante el procesamiento significa que el uso del espacio es constante. Ignorame.
Jules
1

Ruby 47 caracteres

Al igual que Python de @KeithRandall:

f=->n{(0..1<<n).sort_by{|x|x.to_s(2).count ?1}}
steenslag
fuente
1

Mathematica, 26

Tr/@(2^Subsets@Range@#/2)&

Ejemplo:

Tr/@(2^Subsets@Range@#/2)&[4]

{0, 1, 2, 4, 8, 3, 5, 9, 6, 10, 12, 7, 11, 13, 14, 15}

alephalpha
fuente
0

Perl, 64/2 = 32

#!perl -ln
for$i(0..$_){$i-(sprintf"%b",$_)=~y/1//||print for 0..2**$_-1}

Simplemente iterar sobre los [0..2^n-1] n + 1tiempos de rango . En cada iteración imprima solo los números que tienen un número de 1 bits igual a la variable de iteración ( $i). Los bits se cuentan contando1 (y/1// ) en el número convertido a cadena binaria con sprintf.

Prueba a .

Perl, 63

Enfoque de clasificación:

#!perl -l
print for sort{eval+(sprintf"%b-%b",$a,$b)=~y/0//dr}0..2**<>-1
nutki
fuente
1
@Optimizer, utiliza la memoria O (1). ¿Qué otra definición tenemos? Vaya, eso no es cierto, ya que lo
imprimo en
@Optimizer, fijo.
nutki
Bueno, soy consciente de esto cuando establezco la condición, pero lo permito de todos modos, ya que quiero ver qué respuestas complicadas pueden dar las personas.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
2
Acabo de preguntar "cómo", ya que no puedo leer perl :) ¿Le gustaría agregar más explicaciones?
Optimizador
@Optimizer, se agregó alguna explicación más.
nutki
0

Java 8, 205

public class S{public static void main(String[] n){java.util.stream.IntStream.range(0,1<<Integer.parseInt(n[0])).boxed().sorted((a,b)->Integer.bitCount(a)-Integer.bitCount(b)).forEach(System.out::print);}}
cPu1
fuente
0

C ++ 11, 117 caracteres:

using namespace std;int main(){ set<pair<int,int> > s;int b;cin>>b;int i=0;while(++i<pow(2,b))s.insert({bitset<32>(i).count(),i});for (auto it:s) cout <<it.second<<endl;}

Sin golf:

using namespace std;
int main()
{
    set<pair<int,int> > s;
    int b;
    cin>>b;
    int i=0;
    while (++i<pow(2,b))  {
        s.insert({bitset<32>(i).count(),i});
    }
    for (auto it:s) {
        cout <<it.second<<endl;
    }
}

Explicación:

Crea un conjunto de pares int, int. El primer int es el recuento de bits, el segundo es el número. Los pares se comparan según su primer parámetro, por lo que el conjunto se ordena por conteo de bits.

Nuclear
fuente