¿Que viene despues?

15

Dada una lista de enteros separados por espacios, su tarea es encontrar el siguiente entero en la secuencia. Cada número entero en la secuencia es el resultado de aplicar una sola operación matemática ( +, -, *o /) al entero anterior, y cada secuencia se compone de un número variable de dichas operaciones (pero no más de 10). Ninguna secuencia será más larga que la mitad de la secuencia de enteros, por lo que cada secuencia de operaciones aparecerá al menos dos veces para su confirmación.
La entrada será a través de stdin (o promptpara soluciones de JavaScript).

Aquí hay algunos ejemplos explicativos.

Entrada:

1 3 5 7 9 11

Salida:

13

Bastante fácil, este. Todos los valores son valores anteriores +2.

Entrada:

1 3 2 4 3 5 4 6 5 7 6

Ouput:

8

Dos pasos en esta secuencia, +2entonces -1.

Entrada:

2 6 7 3 9 10 6 18 19 15 45 46

Salida:

42

Tres pasos - *3, +1, -4.

Casos de prueba

Aquí hay algunos casos de prueba más:

Entrada:

1024 512 256 128 64 32 16

Salida:

8

Entrada:

1 3 9 8 24 72 71 213 639

Salida:

638

Entrada:

1 2 3 4 5 2 3 4 5 6 3 4 5 6 7

Salida:

4

Entrada:

1 2 4 1 3 9 5 8 32 27 28 56 53 55 165 161 164 656 651 652 1304

Salida:

1301

Tengo una solución Scala sin golf (42 líneas) que publicaré en un par de días.

Este es el código de golf: la respuesta más corta gana.

Gareth
fuente
¿Se garantiza que la división sea exacta?
Peter Taylor
@Peter Sí. Cada paso dará como resultado un número entero.
Gareth
Pero si el paso es "/ 3", ¿se garantiza que el resto siempre será 0?
Peter Taylor
@ Peter Sí, el resto siempre será 0.
Gareth
3
oeis.org
Thomas Eding

Respuestas:

12

Golfscript, 203 138 caracteres

~]0{).2$.);[\(;]zip\/zip{.{~-}%.&({-}+\{;{.0={.~\%{.~%{;0}{~/{/}+}if}{~\/{*}+}if}{~!{;}*}if}%.&(\{;;0}/}{\;}if}%.{!}%1?)!{0}*}do\@)\,@%@=~

Esto usa mucho más ifs que un programa Golfscript estándar, y su funcionamiento es bastante críptico, por lo que aquí hay una versión comentada (pero no descartada que no sea mediante la adición de espacios en blanco y comentarios):

~]0
# Loop over guesses L for the length of the sequence
{
    # [x0 ... xN] L-1
    ).
    # [x0 ... xN] L L
    2$.);[\(;]zip
    # [x0 ... xN] L L [[x0 x1][x1 x2]...[x{N-1} xN]]
    \/zip
    # [x0 ... xN] L [[[x0 x1][xL x{L+1}]...][[x1 x2][x{L+1} x{L+2}]...]...]
    {
        # [x0 ... xN] L [[xi x{i+1}][x{i+L} x{i+L+1}]...]
        # Is there an operation which takes the first element of each pair to the second?
        # Copy the pairs, work out each difference, and remove duplicates
        .{~-}%.&
        # Turn the first difference into an operation
        ({-}+\
        # If there was more than one unique difference, look for a multiplication
        {
            ;
            # [x0 ... xN] L [[xi x{i+1}][x{i+L} x{i+L+1}]...]
            # Do something similar, but working out multiplicative factors
            # Note that if we have [0 0] it could be multiplication by anything, so we remove it.
            # However, they can't all be [0 0] or we'd have only one unique difference
            {
                # [0     0   ] =>
                # [0     _   ] => 0     # a "false" value, because it can't possibly be multiplication
                # [a     a.b'] => {b'*}
                # [a'.b  b   ] => {a'/}
                # [_     _   ] => 0     # ditto
                # This is the obvious place to look for further improvements
                .0={.~\%{.~%{;0}{~/{/}+}if}{~\/{*}+}if}{~!{;}*}if
            }%.&
            # If we have one unique multiplication, even if it's false, keep it.
            # Otherwise discard them and replace them with false.
            (\{;;0}/
        }
        # There was only one unique difference. Discard the pairs
        {\;}if
        # operation - one of 0, {d+}, {m*}, {M/}
    }%
    # [x0 ... xN] L [op0 ... op{L-1}]
    # Is any of the operations false, indicating that we couldn't find a suitable operation?
    .{!}%1?
    # [x0 ... xN] L [op0 ... op{L-1}] idxFalse
    # If idxFalse is -1 then all the ops are ok, and we put a false to exit the loop
    # Otherwise one op failed, so we leave the array of ops, which is non-false, to be popped by the do.
    )!{0}*
}do
# [x0 ... xN] L [op0 ... op{L-1}]
\@)\,@%@=~
# op{(len(Xs)-1)%L} (Xs[-1])

Mi presentación original fue la siguiente en 88 caracteres:

~]:x;2.{;).(2base(;{[{--}{@*\.!+/}]=}%[x.(;2$]zip\,<{~++}%x,.@[*x\]zip<{~~}%)\x(;=!}do\;

Sin embargo, esto intenta calcular las operaciones desde la primera aparición de cada una, por lo que si la operación es multiplicación o división y el argumento la primera vez es 0, se rompe.

Peter Taylor
fuente
1
¡Muchas gracias por publicar una explicación! He estado buscando programas diseccionados de Golfscript para poder tratar de darles más sentido.
migimaru
6

Haskell, 276 261 259 257 243 caracteres

Aquí está mi solución ineficiente. Funciona en enteros ilimitados (y limitados). Esta solución funciona correctamente con una división no exacta (por ejemplo:) 5 / 2 = 2.

import Control.Monad
main=interact$show.n.q read.words
f=flip
q=map
_%0=0
x%y=div x y
s b=[1..]>>=q cycle.(f replicateM$[(+),(*),(%)]>>=f q[-b..b].f)
m l x s=[y!!l|y<-[scanl(f($))(x!!0)s],x==take l y]
n x=(s(maximum$q abs x)>>=m(length x)x)!!0

Cómo funciona: creo todas las secuencias posibles de operaciones (posibles). Luego pruebo contra la secuencia de entrada de números para ver si la secuencia generada creará la entrada. Si es así, devuelve el siguiente número en la secuencia. El código siempre devolverá una respuesta derivada de una secuencia más corta de operaciones. Esto sucede porque la lista de secuencias de operaciones se genera en ese orden. Es arbitrario (pero consistente) decidir entre empates. Por ejemplo, el código devuelve 6o 8para la secuencia 2 4.

Sin golf:

import Control.Monad

main :: IO ()
main = print . next . map read . words =<< getLine

opSequences :: Integral a => a -> [[a -> a]]
opSequences bound = [1 ..] >>= map cycle . (`replicateM` (ops >>= (`map` args) . flip))
  where
    ops = [(+), (*), \x y -> if y == 0 then 0 else div x y]
    args = [-bound .. bound]

match :: (MonadPlus m, Integral a) => [a] -> [a -> a] -> m a
match ns opSeq = guard (ns == take len ms) >> return (ms !! len)
  where
    n0 = ns !! 0
    len = length ns
    ms = scanl (flip ($)) n0 opSeq

next :: Integral a => [a] -> a
next ns = (opSequences bound >>= match ns) !! 0
  where
    bound = maximum $ map abs ns
Thomas Eding
fuente
Buena idea de cómo manejar la división no exacta.
Peter Taylor
Fue un efecto secundario accidental. La búsqueda de una solución fue solo mi idea inicial sobre cómo resolver este problema, en mi opinión, me pareció una tarea más simple que calcular la respuesta.
Thomas Eding
Es Control.Monad -> Monadposible? Y qué talinteract$show.n.q read.words
FUZxxl
6

Python, 333 366 ... 315 303 278 269 261 246 caracteres

n=map(float,raw_input().split())
y=len(n)-1
l=1
def O(f):
 p,q=n[f:y:l],n[f+1::l]
 for a,b in zip(p,q):
    for x in((b-a).__add__,(b/(a or 1)).__mul__):
     if map(x,p)==q:return x
while 1:
 if all(map(O,range(l))):print int(O(y%l)(n[y]));break
 l+=1

Crea operaciones con el primer par de números y verifica en otros pares. Almacena todas las operaciones y, si todas tienen éxito, aplica la operación apropiada en el último elemento de la lista.

Editado: pasa la prueba del mal :-) Ahora busque la operación en todas las posiciones.

Apuesta inicial
fuente
Agradable. Pasa todas mis pruebas, pero no la particularmente malvada de Peter Taylor:0 0 1 2 3 6 7 14
Gareth
0 0 0 0 1 0 0 0 0 1No tiene salida 0.
Thomas Eding
@trinithis Esa entrada no se ajusta a la especificación. La secuencia de operaciones debe repetirse completamente al menos una vez.
Gareth
1
Oooh, aquí hay una mejora divertida: lambda x:x+b-a-> (b-a).__add__. Lástima que sea solo un personaje, estoy aprendiendo mucho sobre Python al hacer esto.
Ni idea
1
Hacer limplícitamente un ahorro global mucho: pastie.org/2416407
Clueless
4

Python, 309 305 295 279 caracteres

Maneja todos los casos de prueba originales, así como el retorcido de Peter Taylor 0 0 1 2 3 6 7 14:

l=map(int,raw_input().split())
i=v=0
while v<1:
 v=i=i+1
 for j in range(i):
    p=zip(l[j::i],l[j+1::i])
    d,r=set(q[1]-q[0]for q in p),set(q[1]*1./(q[0]or 1)for q in p if any(q))
    m,n=len(d)<2,len(r)<2
    v*=m+n
    if(len(l)-1)%i==j:s=l[-1]+d.pop()if m else int(l[-1]*r.pop())
print s

Sin protección, con salida de depuración (muy útil para verificar la corrección):

nums = map(int,raw_input().split())
result = None

for i in range(1,len(nums)/2+1):
    print "-- %s --" % i
    valid = 1
    for j in range(i):
        pairs = zip(nums[j::i], nums[j+1::i])
        print pairs

        diffs = [pair[1] - pair[0] for pair in pairs]
        # this is the tough bit: (3, 6) -> 2, (0, 5) -> 5, (5, 0) -> 0, (0, 0) ignored
        ratios = [float(pair[1])/(pair[0] or 1) for pair in pairs if pair[0] != 0 or pair[1] != 0]

        if len(set(diffs))==1:
            print "  can be diff", diffs[0]
            if (len(nums) - 1) % i == j:
                result = nums[-1] + diffs.pop()
        elif len(set(ratios))==1:
            print "  can be ratio", ratios[0]
            if (len(nums) - 1) % i == j:
                result = int(nums[-1]*ratios.pop())
        else:
            print "** invalid period **"
            valid=0
    if valid and result is not None:
        break

print result

Uso:

echo 0 0 1 2 3 6 7 14 | python whatcomesnext.py
Despistado
fuente
He votado a favor, aunque estrictamente hablando, la entrada debe ser a través de stdin en lugar de argumentos de comando.
Gareth
Eso realmente me permite acortar el programa en cuatro caracteres :)
Clueless
Pocos caracteres, i = v = 0 y mientras v == 0:
Ante el
@Ante gracias, pensé que no podías hacer eso en Python porque la asignación no es una expresión, pero es un dato útil para jugar al golf. Las pestañas literales como la sangría de segundo nivel también ayudan.
Ni idea
No soy un Pythoner, pero parece que estás usando booleanos como enteros en algunas expresiones, y aún así no puedes usar el entero v como un booleano en la prueba while. ¿Está bien? Si es así, seguramente v<1funciona como guardia.
Peter Taylor
2

Rubí 1.9 (437) (521) (447) (477)

Funciona para todos los casos de prueba, incluido el "malvado". Lo jugaré más tarde.

EDITAR: Me di cuenta de que hay otro caso que no estaba manejando correctamente, cuando la continuación necesita usar la operación "misteriosa". La secuencia 2 0 0 -2 -4 -6estaba inicialmente devolviendo 0 en lugar de -12. Ahora lo he arreglado.

EDITAR: se corrigieron un par de casos más y se redujo el código a 447.

EDITAR: Ugh. Tuve que agregar algún código para manejar otras secuencias "malvadas" como0 0 0 6 18 6 12

def v(c,q);t=*q[0];q.size.times{|i|f=c[z=i%k=c.size]
f=c[z]=(g=q[z+k])==0??_:((h=q[z+k+1])%g==0?"*(#{h/g})":"/(#{g/h})")if f==?_
t<<=f==?_?(a=q[i];b=q[i+1].nil?? 0:q[i+1];(a==0&&b==0)||(a!=0&&(b%a==0||a%b==0))?b:0):eval(t.last.to_s+f)}
*r,s=t
(p s;exit)if q==r
end
s=gets.split.map &:to_i
n=[[]]
((s.size-1)/2).times{|i|a,b=s[i,2]
j=["+(#{b-a})"]
j<<=?_ if a==0&&b==0
j<<="*#{b/a}"if a!=0&&b%a==0
j<<="/#{a/b}"if a*b!=0&&a%b==0
n=n.product(j).map(&:flatten)
n.map{|m|v(m*1,s)}}
migimaru
fuente
1

Scala

Esta es la solución que se me ocurrió:

object Z extends App{var i=readLine.split(" ").map(_.toInt)
var s=i.size
var(o,v,f)=(new Array[Int](s),new Array[Double](s),1)
def d(p:Int,j:Array[Int]):Unit={if(p<=s/2){def t(){var a=new Array[Int](s+1)
a(0)=i(0)
for(l<-0 to s-1){o(l%(p+1))match{case 0=>a(l+1)=a(l)+v(l%(p+1)).toInt
case _=>a(l+1)=(a(l).toDouble*v(l%(p+1))).toInt}}
if(a.init.deep==i.deep&&f>0){f^=f
println(a.last)}}
o(p)=0 
v(p)=j(1)-j(0)
t
d(p+1,j.tail)
o(p)=1
v(p)=j(1).toDouble/j(0).toDouble
t
d(p+1,j.tail)}}
d(0,i)
i=i.tail
d(0,i)}

Sin golf:

object Sequence extends App
{
    var input=readLine.split(" ").map(_.toInt)
    var s=input.size
    var (ops,vals,flag)=(new Array[Int](s),new Array[Double](s),1)
    def doSeq(place:Int,ints:Array[Int]):Unit=
    {
        if(place<=s/2) 
        {
            def trysolution()
            {
                var a=new Array[Int](s+1)
                a(0)=input(0)
                for(loop<-0 to s-1)
                {
                    ops(loop%(place+1))match
                    {
                        case 0=>a(loop+1)=a(loop)+vals(loop%(place+1)).toInt
                        case _=>a(loop+1)=(a(loop).toDouble*vals(loop%(place+1))).toInt
                    }
                }
                if(a.init.deep==input.deep&&flag>0)
                {
                    flag^=flag
                    println(a.last)
                }
            }
            ops(place)=0
            vals(place)=ints(1)-ints(0)
            trysolution
            doSeq(place+1,ints.tail)
            ops(place)=1
            vals(place)=ints(1).toDouble/ints(0).toDouble
            trysolution
            doSeq(place+1,ints.tail)
        }
    }
    doSeq(0,input)
    input=input.tail
    doSeq(0,input)
}
Gareth
fuente
¿Cómo lo invoco? echo "0 0 1 2 3 6 7 14" | scala Sequencemantiene la pantalla en negro.
usuario desconocido
@user unknown scala Sequencey luego ingrese la secuencia y presione enter.
Gareth
Ah, usted escribió en el comentario de las preguntas, que no resuelve este específico, funciona con eco-pipe como el anterior para las preguntas solucionables.
usuario desconocido
1

Scala 936

type O=Option[(Char,Int)]
type Q=(O,O)
type L=List[Q]
val N=None
def t(a:Int,b:Int):Q=if(a>b)(Some('-',a-b),(if(b!=0&&b*(a/b)==a)Some('/',a/b)else N))else
(Some('+',b-a),(if(a!=0&&a*(b/a)==b)Some('*',b/a)else N))
def w(a:Q,b:Q)=if(a._1==b._1&&a._2==b._2)a else
if(a._1==b._1)(a._1,N)else
if(a._2==b._2)(N,a._2)else(N,N)
def n(l:L):Q=l match{case Nil=>(N,N)
case x::Nil=>x
case x::y::Nil=>w(x,y)
case x::y::xs=>n(w(x,y)::xs)} 
def z(l:L,w:Int)=for(d<-1 to w)yield
n(l.drop(d-1).sliding(1,w).flatten.toList)
def h(s:L):Boolean=s.isEmpty||(s(0)!=(N,N))&& h(s.tail)
def j(s:L,i:Int=1):Int=if(h(z(s,i).toList))i else j(s,i+1)
def k(b:Int,o:Char,p:Int)=o match{case'+'=>b+p
case'-'=>b-p
case'*'=>b*p
case _=>b/p}
val e=getLine 
val i=e.split(" ").map(_.toInt).toList
val s=i.sliding(2,1).toList.map(l=>t(l(0),l(1)))
val H=n(s.drop(s.size%j(s)).sliding(1,j(s)).flatten.toList)
val c=H._1.getOrElse(H._2.get)
println (k(i(i.size-1),c._1,c._2))

sin golf:

type O = Option[(Char, Int)]

def stepalize (a: Int, b: Int): (O, O) = (a > b) match {
   case true => (Some('-', a-b), (if (b!=0 && b * (a/b) == a) Some ('/', a/b) else None)) 
   case false=> (Some('+', b-a), (if (a!=0 && a * (b/a) == b) Some ('*', b/a) else None)) }

def same (a: (O, O), b: (O, O)) = {
  if (a._1 == b._1 && a._2 == b._2) a else
  if (a._1 == b._1) (a._1, None) else 
  if (a._2 == b._2) (None, a._2) else 
  (None, None)}

def intersection (lc: List[(O, O)]): (O, O) = lc match {
  case Nil => (None, None)
  case x :: Nil => x
  case x :: y :: Nil => same (x, y)
  case x :: y :: xs  => intersection (same (x, y) :: xs)} 

def seriallen (lc: List[(O, O)], w: Int= 1) =
  for (d <- 1 to w) yield 
    intersection (lc.drop (d-1).sliding (1, w).flatten.toList)

def hit (s: List[(O, O)]) : Boolean = s match {
  case Nil => true 
  case x :: xs => (x != (None, None)) && hit (xs)}

def idxHit (s: List[(O, O)], idx: Int = 1) : Int =
  if (hit (seriallen (s, idx).toList)) idx else 
    idxHit (s, idx+1)

def calc (base: Int, op: Char, param: Int) = op match {
  case '+' => base + param
  case '-' => base - param
  case '*' => base * param
  case _   => base / param}

def getOp (e: String) = {
  val i = e.split (" ").map (_.toInt).toList
  val s = i.sliding (2, 1).toList.map (l => stepalize (l(0), l(1)))
  val w = idxHit (s)
  val hit = intersection (s.drop (s.size % w).sliding (1, w).flatten.toList)
  val ci = hit._1.getOrElse (hit._2.get)
  val base = i(i.size - 1)
  println ("i: " + i + " w: " + w + " ci:" + ci + " " + calc (base, ci._1, ci._2))
}

val a="1 3 5 7 9 11"
val b="1 3 2 4 3 5 4 6 5 7 6"
val c="2 6 7 3 9 10 6 18 19 15 45 46"
val d="1024 512 256 128 64 32 16"
val e="1 3 9 8 24 72 71 213 639"
val f="1 2 3 4 5 2 3 4 5 6 3 4 5 6 7"
val g="1 2 4 1 3 9 5 8 32 27 28 56 53 55 165 161 164 656 651 652 1304"
val h="0 0 1 2 3 6 7 14"
val i="0 0 0 0 1 0 0 0 0 1 0"

List (a, b, c, d, e, f, g, h, i).map (getOp)

Falla miserablemente en Peter Taylor h, pero no veo la posibilidad de sanar el programa en un tiempo razonable.

usuario desconocido
fuente
¿Sería útil reducirlo si se trata -como un caso especial de +y /como un caso especial de *? Mi forma de pasar la entrada de Peter Taylor (y similar) fue cortar el primer número de la secuencia e intentar nuevamente. Todavía no he tenido tiempo de ver cómo funciona su programa para saber si eso ayudaría con el suyo.
Gareth
Supongo que ayudaría, pero solo para ese caso especial. Una serie que contiene la multiplicación nula más tarde, como -1, 0, 0, 1, 2, 3, 6, 7, 14necesitará una curación diferente.
usuario desconocido