Was kommt als nächstes?

15

Bei einer durch Leerzeichen getrennten Liste von Ganzzahlen besteht Ihre Aufgabe darin, die nächste Ganzzahl in der Sequenz zu finden. Jede ganze Zahl in der Sequenz ist das Ergebnis eine einzige mathematische Operation der Anwendung ( +, -, *oder /) zur vorherige ganzen Zahl ist , und jede Sequenz wird aus einer variablen Anzahl dieser Operationen aus (aber nicht mehr als 10). Keine Sequenz ist länger als die Hälfte der Sequenz von Ganzzahlen, sodass jede Sequenz von Operationen zur Bestätigung mindestens zweimal angezeigt wird.
Die Eingabe erfolgt über stdin (oder promptfür JavaScript-Lösungen).

Hier einige erläuternde Beispiele.

Eingang:

1 3 5 7 9 11

Ausgabe:

13

Ziemlich einfach. Alle Werte sind Vorgängerwerte +2.

Eingang:

1 3 2 4 3 5 4 6 5 7 6

Ausgang:

8

Zwei Schritte in dieser Reihenfolge, +2dann -1.

Eingang:

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

Ausgabe:

42

Drei Schritte - *3, +1, -4.

Testfälle

Hier noch ein paar Testfälle:

Eingang:

1024 512 256 128 64 32 16

Ausgabe:

8

Eingang:

1 3 9 8 24 72 71 213 639

Ausgabe:

638

Eingang:

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

Ausgabe:

4

Eingang:

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

Ausgabe:

1301

Ich habe eine Scala-Lösung (42 Zeilen), die ich in ein paar Tagen veröffentlichen werde.

Das ist Code-Golf - die kürzeste Antwort gewinnt.

Gareth
quelle
Ist eine genaue Unterteilung garantiert?
Peter Taylor
@ Peter Ja. Jeder Schritt führt zu einer ganzen Zahl.
Gareth
Wenn der Schritt "/ 3" ist, ist dann garantiert, dass der Rest immer 0 ist?
Peter Taylor
@ Peter Ja, der Rest wird immer 0 sein.
Gareth
3
oeis.org
Thomas Eding

Antworten:

12

Golfscript, 203 138 Zeichen

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

Dies verwendet weit mehr ifs als ein Standard-Golfscript-Programm und seine Bedienung ist ziemlich kryptisch.

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

Mein ursprünglicher Beitrag war der folgende mit 88 Zeichen:

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

Hierbei wird jedoch versucht, die Operationen vom ersten Auftreten jeder Operation an zu berechnen. Wenn die Operation also eine Multiplikation oder Division ist und das Argument beim ersten Mal 0 ist, wird sie unterbrochen.

Peter Taylor
quelle
1
Vielen Dank für die Erklärung! Ich habe nach zerlegten Golfscript-Programmen gesucht, damit ich versuchen kann, mehr Sinn daraus zu machen.
Migimaru
6

Haskell, 276 261 259 257 243 Zeichen

Hier ist meine ineffiziente Lösung. Es funktioniert mit unbegrenzten (und begrenzten) ganzen Zahlen. Diese Lösung funktioniert bei nicht exakter Unterteilung (zB:) 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

So funktioniert es: Ich erstelle jede mögliche Folge von (möglichen) Operationen. Dann teste ich anhand der Eingabesequenz von Zahlen, ob die generierte Sequenz die Eingabe erzeugt. Wenn dies der Fall ist, geben Sie die nächste Nummer in der Sequenz zurück. Der Code gibt immer eine Antwort zurück, die aus einer kürzesten Abfolge von Vorgängen abgeleitet wurde. Dies geschieht, weil die Liste der Operationssequenzen in dieser Reihenfolge generiert wird. Es ist willkürlich (aber beständig), sich für eine Verbindung zu entscheiden. Zum Beispiel gibt der Code 6oder 8für die Sequenz zurück 2 4.

Ungolfed:

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
quelle
Gute Idee für den Umgang mit nicht exakter Teilung.
Peter Taylor
Es war eine zufällige Nebenwirkung. Die Suche nach einer Lösung war nur meine anfängliche Idee zur Lösung dieses Problems. Für mich schien es eine einfachere Aufgabe zu sein, als die Antwort zu berechnen.
Thomas Eding
Ist Control.Monad -> Monadmöglich Und wie wäre esinteract$show.n.q read.words
FUZxxl
6

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

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

Erzeugt eine Operation mit dem ersten Zahlenpaar und überprüft sie bei anderen Paaren. Speichert alle Operationen und wendet, wenn alle erfolgreich sind, die entsprechende Operation auf das letzte Listenelement an.

Bearbeitet: Besteht bösen Test :-) Jetzt auf allen Positionen nach Operation suchen.

Ante
quelle
Nett. Besteht alle meine Tests, aber nicht Peter Taylors besonders böse:0 0 1 2 3 6 7 14
Gareth
0 0 0 0 1 0 0 0 0 1wird nicht ausgegeben 0.
Thomas Eding
@trinithis Diese Eingabe entspricht nicht der Spezifikation. Die Abfolge der Vorgänge muss mindestens einmal vollständig wiederholt werden.
Gareth
1
Oooh, hier ist eine lustige Verbesserung: lambda x:x+b-a-> (b-a).__add__. Schade, dass es nur ein Charakter ist, ich lerne so viel über Python, indem ich das mache.
Ahnungslos
1
Etwas herstellen limplizit globale spart eine Menge: pastie.org/2416407
Clueless
4

Python, 309 305 295 279 Zeichen

Behandelt alle Original-Testfälle sowie Peter Taylors knorrigen 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

Ungolfed, mit Debugging-Ausgabe (sehr hilfreich bei der Überprüfung der Korrektheit):

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

Verwendung:

echo 0 0 1 2 3 6 7 14 | python whatcomesnext.py
Ahnungslos
quelle
Ich habe upvoted, obwohl die Eingabe streng genommen über stdin und nicht über Befehlsargumente erfolgen sollte.
Gareth
Dadurch kann ich das Programm tatsächlich um vier Zeichen kürzen :)
Ahnungslos
Wenige Zeichen, i = v = 0 und während v == 0:
Ante
@Ante danke, ich dachte, Sie könnten das nicht in Python tun, weil Zuweisung kein Ausdruck ist, aber es ist ein hilfreicher Leckerbissen für das Golfen. Literal-Tabulatoren als Einrückung der zweiten Ebene helfen ebenfalls.
Ahnungslos
Ich bin kein Pythoner, aber Sie scheinen in einigen Ausdrücken Boolesche Werte als Ganzzahlen zu verwenden und können im while-Test Integer v nicht als Boolesche Werte verwenden. Ist das richtig? Wenn ja, arbeitet sicherlich v<1als Wache.
Peter Taylor
2

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

Funktioniert für alle Testfälle, einschließlich der "bösen". Ich werde später mehr Golf spielen.

BEARBEITEN: Mir ist aufgefallen, dass es einen anderen Fall gibt, den ich nicht richtig behandelt habe - wenn die Fortsetzung die "Rätsel" -Operation verwenden muss. Die Sequenz 2 0 0 -2 -4 -6gab anfangs 0 anstelle von -12 zurück. Ich habe das jetzt behoben.

BEARBEITEN: Einige Randfälle wurden behoben und der Code auf 447 reduziert.

EDIT: Ugh. Musste etwas Code hinzufügen, um andere "böse" Sequenzen wie z0 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
quelle
1

Scala

Dies ist die Lösung, die ich mir ausgedacht habe:

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

Ungolfed:

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
quelle
Wie rufe ich es auf? echo "0 0 1 2 3 6 7 14" | scala SequenceHält den Bildschirm schwarz.
Benutzer unbekannt
@user unknown scala Sequenceund geben Sie die Sequenz ein und drücken Sie die Eingabetaste.
Gareth
Ah, Sie haben im Fragenkommentar geschrieben, dass Sie diese spezielle Frage nicht lösen - es funktioniert mit der Echopipe wie oben für die lösbaren Fragen.
Benutzer unbekannt
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))

ungolfed:

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)

Scheitert kläglich an Peter Taylors h, aber ich sehe keine Möglichkeit, das Programm in angemessener Zeit zu heilen.

Benutzer unbekannt
quelle
Würde es helfen, es zu verkleinern, wenn Sie -als Sonderfall von +und /als Sonderfall von behandelt würden *? Meine Art, Peter Taylors (und ähnliche) Eingaben weiterzugeben, bestand darin, die erste Zahl in der Sequenz abzuschneiden und es erneut zu versuchen. Ich hatte noch keine Zeit zu schauen, wie Ihr Programm funktioniert, um zu wissen, ob das bei Ihnen helfen würde.
Gareth
Ich denke, es würde helfen, aber nur für diesen speziellen Fall. Eine Reihe, die später die Null-Multiplikation enthält, -1, 0, 0, 1, 2, 3, 6, 7, 14wird eine andere Heilung benötigen.
Benutzer unbekannt