Jakie są powtarzające się cyfry Fibonacciego?

30

Jak zapewne wiesz, liczba Fibonacciego jest liczbą będącą sumą dwóch poprzednich liczb w szeregu.

Fibonacci Digit ™ to taki, który jest sumą dwóch poprzednich cyfr .

Na przykład, dla początku serii 1,1, seria będzie następować 1,1,2,3,5,8,13,4,7,11,2.... Zmiana następuje po tym 13, gdzie zamiast dodawać 8+13dodajesz 1+3. Seria zapętla się na końcu, gdzie 4+7=11i 1+1=2tak samo jak seria się zaczyna.

Dla innego przykładu, seria zaczynając 2,2: 2,2,4,6,10,1,1,2,3,5,8,13,4,7,11,2,3.... Ten zaczyna się wyjątkowo, ale gdy suma cyfr się 10skończy, skończysz 1+0=1, 0+1=1, a seria będzie kontynuowana - i zapętla się - w taki sam sposób jak 1,1seria.


Wyzwanie

Biorąc pod uwagę liczbę całkowitą 0≤n≤99, obliczyć pętlę w szeregu cyfr Fibonacciego zaczynając od tych dwóch cyfr. (Ty z pewnością pozwoliło rozważyć całkowite z tego zakresu, ale nie jest to wymagane). Jeśli dana wejście jedno-cyfrowy kod należy interpretować je oznaczają początek serii 0,n.

Wszystkie liczby w pętli, które są dwucyfrowe, muszą być wyprowadzone jako dwie cyfry. Na przykład pętla for 1,1zawierałaby 13, a nie 1,3.

Wyjście zaczyna się od pierwszej liczby w pętli. Opierając się na powyższych ograniczeniach, pętla dla 1,1zaczyna się 2od, ponieważ 1,1i 11są liczone osobno.

Każda liczba danych wyjściowych może być oddzielona przez cokolwiek chcesz, o ile jest spójna. We wszystkich moich przykładach używam przecinków, ale spacje, podziały wierszy, losowe litery itp. Są dozwolone, o ile zawsze używasz tej samej separacji. Tak więc 2g3g5g8g13g4g7g11jest to legalne wyjście 1, ale 2j3g5i8s13m4g7sk11nie jest. Możesz używać ciągów, list, tablic, cokolwiek, pod warunkiem, że masz prawidłowe liczby we właściwej kolejności oddzielone spójnym separatorem. Dopuszcza się braketing całego wyjścia (np. (5,9,14)Lub [5,9,14]itp.).

Przypadki testowe:

1 -> 2,3,5,8,13,4,7,11
2 -> 2,3,5,8,13,4,7,11
3 -> 11,2,3,5,8,13,4,7
4 -> 3,5,8,13,4,7,11,2
5 -> 2,3,5,8,13,4,7,11
6 -> 3,5,8,13,4,7,11,2
7 -> 14,5,9
8 -> 13,4,7,11,2,3,5,8
9 -> 11,2,3,5,8,13,4,7
0 -> 0
14 -> 5,9,14
59 -> 5,9,14

To jest , więc wygrywa najmniejsza liczba bajtów.

DonielF
źródło
1
Can we take 2 digits as input, instead of 0n99?
Arnauld
1
As in, take two inputs rather than one input that’s split? No.
DonielF
I still don't understand why 14 and 59 give the same result. If 59 is interpreted as starting 5,9 and allowing that as part of the loop then surely 14 should be the start of its loop?
Neil
1
@williamporter The beginning of the sequence is 0,1,1,2,3,5,8,13,4,7,11,2,3. The first time that the loop repeats is at the second 2.
DonielF
2
@Neil The beginning of those respective sequences is 1,4,5,9,14,5 and 5,9,14,5,9. Both of them repeat beginning with the second 5. As I said earlier, only the input is split up; later numbers keep their digits together in the sequence.
DonielF

Odpowiedzi:

10

Jelly, 15 bytes

DFṫ-SṭḊ
d⁵ÇÐḶZḢ

Try it online!

How it works

d⁵ÇÐḶZḢ  Main link. Argument: n (integer)

d⁵       Divmod 10; yield [n:10, n%10].
  ÇÐḶ    Call the helper link until a loop is reached. Return the loop.
     Z   Zip/transpose the resulting array of pairs.
      Ḣ  Head; extract the first row.


DFṫ-SṭḊ  Helper link. Argument: [a, b] (integer pair)

D        Decimal; replace a and b with the digits in base 10.
 F       Flatten the resulting array of digit arrays.
  ṫ-     Tail -1; take the last two digits.
    S    Compute their sum.
      Ḋ  Dequeue; yield [b].
     ṭ   Append the sum to [b].
Dennis
źródło
6

Perl 6, 96 78 75 bytes

-3 bytes thanks to nwellnhof

{0,|.comb,((*~*)%100).comb.sum...{my$a=.tail(2);m/(\s$a.*)$a/}o{@_};$_&&$0}

Try it online!

0 returns 0, and other number return a Match object which stringifies to the numbers separated by a space with a leading a trailing space.

Explanation:

{                                                                         }   # Anonymous code block
 0,|.comb,                    ...   # Start a sequence with 0,input
                                    # Where each element is
                          .sum      # The sum of
          (     %100).comb          # The last two digits
           (*~*)                    # Of the previous two elements joined together
                                                                         # Until
                                 {                           }o{@_}   # Pass the list into another function
                                  my$a=.tail(2); # Save the last two elements
                                                m/(\s$a.*)$a/  # The list contains these elements twice?
                                                                     # And return
                                                                   ;$_     # Input if input is 0
                                                                      &&   # Else
                                                                        $0 # The looping part, as matched
Jo King
źródło
5

JavaScript (ES6),  111 104  103 bytes

f=(n,o=[p=n/10|0,n%10])=>n^o[i=o.lastIndexOf(n=(q=p+[p=n])/10%10+q%10|0)-1]?f(n,[...o,n]):o.slice(i,-1)

Try it online!

Commented

f = (                       // f = recursive function taking:
  n,                        //    n = last term, initialized to the input
  o = [                     //    o = sequence, initially containing:
    p = n / 10 | 0,         //      p = previous term, initialized to floor(n / 10)
    n % 10 ]                //      n mod 10
) =>                        //
  n ^                       // we compare n against
  o[                        // the element in o[] located at
    i = o.lastIndexOf(      //   the index i defined as the last position of
      n =                   //     the next term:
        (q = p + [p = n])   //       q = concatenation of p and n; update p to n
        / 10 % 10           //       compute the sum of the last two digits
        + q % 10            //       of the resulting string
        | 0                 //       and coerce it back to an integer
      ) - 1                 //   minus 1
  ] ?                       // if o[i] is not equal to n:
    f(n, [...o, n])         //   append n to o[] and do a recursive call
  :                         // else:
    o.slice(i, -1)          //   we've found the cycle: return it
Arnauld
źródło
5

Python 3, 187 176 158 139 138 129 121 120 112 96 95 120 116 bytes

f=lambda n,m=0,z=[]:(n,m)in zip(z,z[1:])and z[z.index(m)::-1]or f((z and n//10or m%10)+n%10,z and n or n//10,(m,*z))

Try it online!

Edit: As noted by @Jules, shorter solution applies to Python 3.6+. No longer distinct solutions for Python 3 / 3.6+

Edit: Indexing of z was too verbose. Without that now there is no gain in using eval.

Edit: Simplified finding if last two elements already appeared in the sequence.

Edit: Changed output format from list to tuple + replaced lambda with def

Edit: Back to lambda but embedded t into f.

Edit: Input n can be actually interpreted as head of growing collection z which would represent tail in recursive approach. Also beats @Arbo's solution again.

Edit: Actually you can unpack two items from head which cuts another 16 bytes.

Edit: Actually 17 bytes.

Edit: As noted by @Arbo solution was giving answers for 14 and 59 cases as they were in initial test cases which were proven later to be wrong. For now this isn't so short but at least it works correctly.


Quite an abuse of f-strings and eval. Original ungolfed code although I suspect it could be done somehow easier:

def is_subsequence(l1, l2):
    N, n = len(l1), len(l2)
    for i in range(N-n):
        if l1[i:i+n]==l2:
            return True
    return False

def generate_sequence(r):
    if is_subsequence(r,r[-2:]):
        return r
    last_two_digits = "".join(map(str,r))[-2:]
    new_item = sum(int(digit) for digit in last_two_digits)
    return generate_sequence(r + [new_item])

def f(n):
    seq = generate_sequence([n,n])[::-1]
    second_to_last = seq[1]
    first_occurence = seq.index(second_to_last)
    second_occurence = seq.index(second_to_last, first_occurence + 1)
    return seq[first_occurence + 1 : second_occurence + 1][::-1]
Nishioka
źródło
1
Small correction: this is Python 3.6+. This will plainly not work in 3.5 or older.
0xdd
1
Your testing code seems to not work; an input of 59 yields (14, 5, 9)
ArBo
I see that test cases have changed since I began the challenge so that's why there was incorrect output. I've changed my solution so that it works but for now it's not so short. Nevertheless thanks for pointing that out.
Nishioka
4

C (gcc), 114 112 109 bytes

f(n,s){int i[19]={};for(s=n/10,n%=10;i[s]-n;n+=n>9?-9:s%10,s=i[s])i[s]=n;for(;printf("%d ",s),i[s=i[s]]-n;);}

Try it online!

-3 from ceilingcat

Includes a trailing space.

f(n,s){
    int i[19]={};                               //re-initialize edges for each call
    for(s=n/10,n%=10;                           //initialize from input
        i[s]-n;                                 //detect loop when an edge s->n repeats
        n+=n>9?-9:s%10,s=i[s])i[s]=n;           //step
    for(;printf("%d ",s),i[s=i[s]]-n;);         //output loop
}
attinat
źródło
1
huh, do...while doesn't need the braces if it's a single statement O_o
ASCII-only
3

Perl 5, 90 76 bytes

s/.\K/ /;s/(.?) *(.)\K$/$".($1+$2)/e until/^0|\b(.\B.|. .)\b.*(?= \1)/;$_=$&

TIO

Nahuel Fouilleul
źródło
@JoKing, fixed and optimized
Nahuel Fouilleul
2

Java (JDK), 194 bytes

n->"acdfinehlcdfinehfjofj".chars().map(x->x-97).skip((n="abbicbcsfibbbgqifiibbgbbbcsfbiiqcigcibiccisbcqbgcfbffifbicdqcibcbicfsisiibicfsiffbbicfsifiibicfsifii".charAt(n)%97)).limit(n<1?1:n<9?8:3)

Try it online!

Hardcoded seemed the shortest given that Python already had an answer of 187...

Olivier Grégoire
źródło
2

Haskell, 100 bytes

d!p@(s,t)|(_,i:h)<-span(/=p)d=fst<$>i:h|q<-d++[p]=q!(t,last$mod s 10+t:[t-9|t>9])
h x=[]!divMod x 10

Try it online!

d!p@(s,t)                -- function '!' recursively calculates the sequence
                         -- input parameter:
                         -- 'p': pair (s,t) of the last two numbers of the sequence
                         -- 'd': a list of all such pairs 'p' seen before
  |       <-span(/=p)d   -- split list 'd' into two lists, just before the first
                         -- element that is equal to 'p'
   (_,i:h)               -- if the 2nd part is not empty, i.e. 'p' has been seen
                         -- before
          =fst<$>i:h     -- return all first elements of that 2nd part. This is
                         -- the result.
  |q<-d++[p]             -- else (p has not been seen) bind 'q' to 'd' followed by 'p'
   =q!                   -- and make a recursive call to '!' with 'q' and
     (t,    )            -- make the last element 't' the second to last element
                         -- the new last element is
          [t-9|t>9]      -- 't'-9 (digit sum of 't'), if 't'>9
       mod s 10+t        -- last digit of 's' plus 't', otherwise

h x=                     -- main function
     []!divMod x 10      -- call '!' with and empty list for 'd' and
                         -- (x/10,x%10) as the pair of last numbers
nimi
źródło
2

Python 2, 123 114 113 bytes

n=input()
p=b=l=n/10,n%10
while~-(b in p):p+=b,;l+=(b[1]/10or b[0]%10)+b[1]%10,;b=l[-2:]
print l[p.index(b)-2:-2]

Try it online!

The program builds up a tuple p of all 2-value pairs that have occurred in the sequence, which is initialised with junk to save some bytes. The sequence itself gets built in the tuple l, and the last two elements of this tuple are stored in b for easy (and short) reference. As soon as a repeat is found, we can look up the index of b in p to know where the loop began.

EDIT: Cleaned this up a bit, and shaved off one more byte... My method does seem to be nearing its byte count limit, and I really should stop working on this.

ArBo
źródło
1

Charcoal, 46 bytes

≔E◧S²ΣιθW¬υ≔ΦE⊖L⊞OθΣ…⮌⪫θω²✂θλLθ¹⁼κ✂θ⊗⁻λLθλ¹υIυ

Try it online! Link is to verbose version of code. Explanation:

≔E◧S²Σιθ

Input the number, pad it to 2 characters, then take the digital sum of each character, and save the resulting list.

W¬υ

Repeat while the list of loops is empty.

⊞OθΣ…⮌⪫θω²

Calculate the sum of the two previous digits and add it to the Fibonacci list.

E⊖L...✂θλLθ¹

Take all the nontrivial suffixes of the list.

≔Φ...⁼κ✂θ⊗⁻λLθλ¹υ

Filter out those that don't repeat and save the result in the list of loops.

Iυ

Cast the list of loops to string and print.

Neil
źródło
1

Red, 189 178 164 137 bytes

func[n][b: n % 10 c: reduce[a: n / 10]until[append c e: b
b: a *(pick[0 1]b > 9)+(a: b % 10)+(b / 10)k: find c reduce[e b]]take/last k k]

Try it online!

Galen Ivanov
źródło
1

Python 2, 149 139 bytes

s=input()
s=[s/10,s%10]
while zip(s,s[1:]).count((s[-2],s[-1]))<2:s+=[(s[-1]/10or s[-2]%10)+s[-1]%10]
print s[-s[::-1].index(s[-2],2)-1:-2]

Try it online!

Expects a non-negative integer as input. Smaller bytecount, but likely will no longer work for integers >99.

Explanation:

# get the input from STDIN
s=input()
# convert the input into two integers via a divmod operation
s=[s/10,s%10]
# count number of times the last two numbers appear in sequence in list.
# turn list into list of adjacent value pairs Ex: [1,1,2]->[(1,1),(1,2)]
      zip(s,s[1:])
                  # count number of times the last two items in list appear in entire list
                  .count((s[-2],s[-1]))
# if >1 matches, we have found a repeat.
while .................................<2:
        # the first digit of the last number, if it is >9
        # else the last digit of the second to last number
        (s[-1]/10or s[-2]%10)
                             # the last digit of the last number
                             +s[-1]%10
    # add the new item to the list
    s+=[..............................]
         # reverse the list, then find the second occurrence of the second to last item
         s[::-1].index(s[-2],2)
# get the section of the list from the second occurrence from the end, discard the final two items of the list
print s[-......................-1:-2]
Triggernometry
źródło