Que ce passe t-il après?

15

Étant donné une liste d'entiers séparés par des espaces, votre tâche consiste à trouver le prochain entier dans la séquence. Chaque nombre entier dans la séquence est le résultat de l' application d' une opération mathématique unique ( +, -, *ou /) à l'entier précédent, et chaque séquence est composée d'un nombre variable de ces opérations (mais pas plus de 10). Aucune séquence ne dépassera la moitié de la longueur de la séquence d'entiers, vous devrez donc faire apparaître chaque séquence d'opérations au moins deux fois pour confirmation.
L'entrée se fera via stdin (ou promptpour les solutions JavaScript).

Voici quelques exemples explicatifs.

Contribution:

1 3 5 7 9 11

Production:

13

Assez facile, celui-ci. Toutes les valeurs sont la valeur précédente +2.

Contribution:

1 3 2 4 3 5 4 6 5 7 6

Sortie:

8

Deux étapes dans cette séquence, +2alors -1.

Contribution:

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

Production:

42

Trois étapes - *3, +1, -4.

Cas de test

Voici quelques cas de test supplémentaires:

Contribution:

1024 512 256 128 64 32 16

Production:

8

Contribution:

1 3 9 8 24 72 71 213 639

Production:

638

Contribution:

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

Production:

4

Contribution:

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

Production:

1301

J'ai une solution Scala non golfée (42 lignes) que je posterai dans quelques jours.

C'est le golf de code - la réponse la plus courte l'emporte.

Gareth
la source
La division est-elle garantie pour être exacte?
Peter Taylor
@Peter Oui. Chaque étape se traduira par un entier.
Gareth
Mais si l'étape est "/ 3", est-il garanti que le reste sera toujours 0?
Peter Taylor
@Peter Oui, le reste sera toujours 0.
Gareth
3
oeis.org
Thomas Eding

Réponses:

12

Golfscript, 203 138 caractères

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

Cela utilise beaucoup plus de ifs qu'un programme Golfscript standard, et son fonctionnement est assez cryptique, alors voici une version commentée (mais non dissociée autrement que par l'ajout d'espaces et de commentaires):

~]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])

Ma soumission originale était la suivante à 88 caractères:

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

Cependant, cela essaie de calculer les opérations à partir de la première occurrence de chacune, donc si l'opération est une multiplication ou une division et que l'argument la première fois est 0, elle se casse.

Peter Taylor
la source
1
Merci beaucoup d'avoir posté une explication! Je cherchais des programmes Golfscript disséqués afin que je puisse essayer de leur donner plus de sens.
migimaru
6

Haskell, 276 261 259 257 243 caractères

Voici ma solution inefficace. Il fonctionne sur des entiers illimités (et bornés). Cette solution se trouve fonctionner correctement avec une division non exacte (par exemple:) 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

Comment ça marche: je crée toutes les séquences possibles d'opérations (possibles). Ensuite, je teste la séquence de nombres entrée pour voir si la séquence générée créera l'entrée. Si c'est le cas, renvoyez le numéro suivant de la séquence. Le code renvoie toujours une réponse dérivée d'une séquence d'opérations la plus courte. Cela se produit car la liste des séquences d'opérations est générée dans cet ordre. C'est arbitraire (mais cohérent) de décider entre les liens. Par exemple, le code renvoie 6ou 8pour la séquence 2 4.

Non 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
la source
Belle idée sur la façon de gérer la division non exacte.
Peter Taylor
C'était un effet secondaire accidentel. La recherche d'une solution n'était que mon idée initiale sur la façon de résoudre ce problème, car pour moi, cela semblait être une tâche plus simple que de calculer la réponse.
Thomas Eding
Est-ce Control.Monad -> Monadpossible? Et que diriez-vousinteract$show.n.q read.words
FUZxxl
6

Python, 333 366 ... 315 303 278 269 261 246 caractères

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

Crée une opération avec la première paire de nombres et vérifie-la sur les autres paires. Stocke toutes les opérations et si toutes réussissent, applique alors l'opération appropriée sur le dernier élément de la liste.

Modifié: passe le test diabolique :-) Maintenant, recherchez l'opération sur toutes les positions.

Ante
la source
Agréable. Réussit tous mes tests, mais pas celui particulièrement mauvais de Peter Taylor:0 0 1 2 3 6 7 14
Gareth
0 0 0 0 1 0 0 0 0 1ne sort pas 0.
Thomas Eding
@trinithis Cette entrée n'est pas conforme à la spécification. La séquence des opérations doit se répéter complètement au moins une fois.
Gareth
1
Oooh, voici une amélioration amusante: lambda x:x+b-a-> (b-a).__add__. Dommage que ce ne soit qu'un seul personnage, j'apprends tellement de choses sur python en les faisant.
Clueless
1
Rendre limplicitement global sauve beaucoup: pastie.org/2416407
Clueless
4

Python, 309 305 295 279 caractères

Gère tous les cas de test d'origine, ainsi que celui 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

Non golfé, avec sortie de débogage (très utile pour vérifier l'exactitude):

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

Usage:

echo 0 0 1 2 3 6 7 14 | python whatcomesnext.py
Aucune idée
la source
J'ai voté positivement, bien qu'à proprement parler, l'entrée devrait être via stdin plutôt que des arguments de commande.
Gareth
Cela me permet en fait de raccourcir le programme de quatre caractères :)
Clueless
Peu de caractères, i = v = 0 et tandis que v == 0:
Ante
@Ante merci, je pensais que vous ne pouviez pas faire ça en python car l'affectation n'est pas une expression, mais c'est une friandise utile pour le golf. Les onglets littéraux comme l'indentation de deuxième niveau sont également utiles.
Clueless
Je ne suis pas un Pythoner, mais vous semblez utiliser des booléens comme entiers dans certaines expressions, et pourtant vous ne pouvez pas utiliser l'entier v comme booléen dans le test while. Est-ce correct? Si c'est le cas, v<1travaille sûrement comme gardien.
Peter Taylor
2

Rubis 1,9 (437) (521) (447) (477)

Fonctionne pour tous les cas de test, y compris le "mal". Je jouerai au golf plus tard.

EDIT: J'ai réalisé qu'il y avait un autre cas que je ne traitais pas correctement - lorsque la suite doit utiliser l'opération "mystère". La séquence 2 0 0 -2 -4 -6renvoyait initialement 0 au lieu de -12. J'ai maintenant corrigé cela.

EDIT: correction de quelques cas supplémentaires et réduction du code à 447.

EDIT: Ugh. J'ai dû ajouter du code pour gérer d'autres séquences "diaboliques" telles que0 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
la source
1

Scala

Voici la solution que j'ai trouvée:

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)}

Non 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
la source
Comment l'invoquer? echo "0 0 1 2 3 6 7 14" | scala Sequencegarde l'écran noir.
utilisateur inconnu
@user unknown scala Sequence, puis entrez la séquence et appuyez sur Entrée.
Gareth
Ah, vous avez écrit dans le commentaire des questions, que vous ne résolvez pas celui-ci - cela fonctionne avec echo-pipe comme ci-dessus pour les questions résolubles.
utilisateur inconnu
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))

non 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)

Échoue lamentablement sur Peter Taylor h, mais je ne vois pas la possibilité de guérir le programme dans un délai raisonnable.

Utilisateur inconnu
la source
Serait-il utile de la réduire si vous la considérez -comme un cas spécial +et /comme un cas spécial *? Ma façon de passer l'entrée de Peter Taylor (et similaire) était de couper le premier numéro de la séquence et d'essayer à nouveau. Je n'ai pas encore eu le temps de voir comment fonctionne votre programme pour savoir si cela pourrait vous aider.
Gareth
Je suppose que cela aiderait, mais uniquement pour ce cas particulier. Une série qui contient la multiplication nulle plus tard, comme, -1, 0, 0, 1, 2, 3, 6, 7, 14aura besoin d'une guérison différente.
utilisateur inconnu