フィボナッチ分解


21

フィボナッチ数

フィボナッチ数で始まるf(1) = 1f(2) = 1(いくつかは、f(0) = 0これは、この挑戦とは無関係である。その後、のためにn > 2f(n) = f(n-1) + f(n-2)

チャレンジ

あなたの仕事はn、フィボナッチ数の積として表現できる正の正の数を見つけて出力することです。インデックスを0にするか、インデックスを1にするか、どちらか適切な方を選択できますが、回答でこれを指定する必要があります。

また、あなたの答えは、妥当な時間で100番目の用語を計算する必要があります。

テストケース

n   result corresponding product (for reference)
1   1      1
2   2      2
3   3      3
4   4      2*2
5   5      5
6   6      2*3
7   8      2*2*2 or 8
8   9      3*3
9   10     2*5
10  12     2*2*3
11  13     13
12  15     3*5
13  16     2*2*2*2 or 2*8
14  18     2*3*3
15  20     2*2*5
16  21     21
17  24     2*2*2*3 or 3*8
18  25     5*5
19  26     2*13
20  27     3*3*3
100 315    3*5*21

参照資料


テストケースでは、それらの一部がn = resultであるのに対し、7以上では等しくないのはなぜですか。たぶん私は質問を理解していません。しかし、確認したいだけです
ジョージ

1
7フィボナッチ数の積として表現することはできません。したがって、1stに必要な数は12ndは2...、6thは6ですが、7thは8です。
リーキー修道女

ああ、それは理にかなっています
ジョージ

あなたは数字を作る際にすべての方法を印刷する必要があります。たとえば、16には2つの方法がありますか、それとも1つだけを出力できますか?
ジョージ

3
@george「corresponding product」は説明のためだけのものだと思います。コードで出力する必要があるのは「result」のみです。
-trichoplax

回答:


6

ゼリー26 24 23 21 バイト

ÆDf÷߀FðḊ¡
1ç#2+С1¤Ṫ

オンラインでお試しください!

使い方

1ç#2+С1¤Ṫ  Main link. Argument: n (integer)

        ¤   Combine the three links to the left into a niladic chain.
   2          Set the left argument and the return value to 2 (third positive
              Fibonacci number).
       1      Yield 1 (second positive Fibonacci number).
    +С       Compute the sum of the return value and right argument, replacing the
              return value with the sum and the right argument with the previous
              return value.
              Do this n times, collecting all return values in a list.
              This returns A, the first n Fibonacci numbers greater than 1.
1             Set the return value to 1.
 ç#           Call the helper link with left argument k = 1, 2, 3... and right
              argument A = [2, 3, 5...] until n of them return a truthy value.
              Collect the matches in a list.
           Ṫ  Tail; extract the last (n-th) match.


ÆDf÷߀FðḊ¡    Helper link. Left argument: k. Right argument: A

        Ḋ     Dequeue; yield r := [2, ..., k].
       ð ¡    If r in non-empty, execute the chain to the left. Return k otherwise.
ÆD              Yield the positive divisors of k.
   ÷            Divide k by all Fibonacci numbers in A.
  f             Filter; keep divisors that belong to k÷A, i.e., all divisors
                d for which k÷d belongs to A.
    ߀          Recursively call the helper link for each kept divisor d, with left
                argument d and right argument A.
      F         Flatten the result, yielding a non-empty array iff any of the
                recursive calls yielded a non-empty array or a number.
                If the left argument is 1, the helper link returns 1, so the
                array will be non-empty if the consecutive divisions by Fibonacci
                numbers eventually produced a 1.

2
入力に関して、このアルゴリズムの複雑さは何ですか?
リーキー修道女

いずれにせよ、それは非常に高速です!100期目は2秒未満
ルイスメンドー

@LeakyNunそれを計算する方法はわかりませんが、入力400が入力100の32倍の時間がかかるのを見ると、指数関数的だと思います。ただし、100を簡単に処理します。
デニス

1
さて、あなただけは...あなたのアルゴリズムが何であるかを知っている
漏れ修道女

テストしたすべての数値に対してフィボナッチ数列を再計算しないことで、なんとか高速化できました。ゴルフが終わったらすぐに説明を追加します。
デニス

5

ジュリア、79バイト

!k=any(i->√(5i^2+[4,-4])%1k%i<!(k÷i),2:k)^~-k
<|(n,k=1)=n>0?n-!k<|-~k:~-k

オンラインでお試しください!

バックグラウンド

高度な問題と解決策、H-187:フィボナッチは正方形であり、提案者が示すことは、

フィボナッチ/ルーカスのアイデンティティ

ここで、L nn 番目の ルーカス数を示し、逆に-

コンバースフィボナッチ/ルーカスアイデンティティ

次いで、Nフィボナッチ数であり、mはルーカス番号です。

使い方

<|目的のために二項演算子を定義します。Juliaの最近のバージョンでは未定義ですが、パーサーによって演算子としてまだ認識されています。

1つの引数(n)のみで呼び出された場合、k1<|初期化します。一方、nは正であり、それは減算!K1た場合、kはフィボナッチ数の積であり、0でない場合)からNと再帰的に、インクリメント自体を呼び出すKにより1。いったんN到達0を、製品の所望の量が発見されたので、以前の値を返しK、すなわち、1 - 〜-k = kが<|

!フィボナッチ数積のテストとして再定義された単項演算子は、次のようにタスクを達成します。

  • k = 1の場合、kはフィボナッチ数の積です。この場合、戻り値のany(...)累乗〜-k = k-1 = 0なので、結果は1になります。

  • 場合K> 1、結果はの値になりany(....)返された、真の場合にのみ述語場合√(5i^2+[4,-4])%1∋k%i<!(k÷i)戻るいくつかの整数のために、私はそのような2≤I≤K

    場合は、述語ホールドで連鎖条件k%iに所属√(5i^2+[4,-4])%1し、k%i未満です!(k÷i)

    • √(5i^2+[4,-4])%1平方根をとる5I 2 + 4及び5I 2 - 4およびそれらの残基はモジュロ演算する1。対応する数値が完全な正方形の場合、各モジュラスは0で、それ以外の場合は1未満の正の数値です。

      以来k%i戻り整数、それだけモジュラスのアレイに属することができる場合のk%iは= 0(すなわち、kはで割り切れるI)とのうちの少なくとも一つ5I 2 + 4及び5I 2 - 4完璧な正方形(すなわち、ありますiはフィボナッチ数です)。

    • !(k÷i)引数k÷i(整数除算)で1を再帰的に呼び出します。これは、k÷iがフィボナッチ数の積である場合に限り、0より大きくなります。

誘導により、目的のプロパティがあります。


5

Python、90バイト

f=lambda n,a=2,b=3:n<2or n%a<f(n/a)or n-a>0<f(n,b,a+b)
g=lambda k,n=1:k and-~g(k-f(n),n+1)

メイン関数gは、kインデックスが1番目のフィボナッチ積を出力します。ほぼ瞬時に計算g(100)315ます。それは、関数を満足させるインスタンスをn探すために数を数える一般的な再帰レシピでそうkなりますf。そのような各インスタンスは、kに達するまで必要な数を減らし0ます。

補助関数はf、数値がフィボナッチ積であることをテストします。オプションの引数aとでフィボナッチ数を再帰的に生成しますb。次のいずれかに該当する場合、「yes」を出力します。

  • n<2。これn==1は、些細な製品を意味します)
  • n%a<f(n/a)。これにはn%a==0およびが必要ですf(n/a)==True。つまりn、フィボナッチ数の倍数であり、aこの要素を除去してaもフィボナッチ積が得られます。
  • n-a>0<f(n,b,a+b)、と同等n>a and f(n,b,a+b)。テストされている現在のフィボナッチ数が少なくともnでなく、いくつかのより大きいフィボナッチ数が機能することを確認します。の代わりに不等式短絡を使用して2バイトを節約してくれたDennisに感謝しますand

関数gは、次のように1バイト短くすることができます。

lambda k:filter(f,range(k*k+1))[k]

if g(k)が常にせいぜいk*k、それが漸近的に正しいかどうかはわかりません。限界は2**k十分ですが、g(100)時間がかかりすぎます。代わりにの再帰をg行うことができますf


OEISのこの表によると、いつg(k)以上k*kk = 47000なります。
-isaacg

2

Perl 6の 95の  93バイト

{(1..*).grep({$/=$_;map {->{$/%$_||($//=$_);$/}...*!%%$_;0},reverse 2,3,&[+]...*>$_;2>$/})[$_]}
{(1..*).grep({$/=$_;map {->{$/%$_||($//=$_);$/}...*%$_;0},reverse 2,3,&[+]...*>$_;2>$/})[$_]}

(0ベースのインデックス)

テスト:

my &fib-prod = {(1..*).grep({$/=$_;map {->{$/%$_||($//=$_);$/}...*%$_;0},reverse 2,3,&[+]...*>$_;2>$/})[$_]}

say fib-prod 0 ..^ 20;
# (1 2 3 4 5 6 8 9 10 12 13 15 16 18 20 21 24 25 26 27)
say time-this { say fib-prod 100 -1; };
# 315
# 1.05135779

sub time-this (&code) {
  my $start = now;
  code();
  now - $start;
}

説明:

{
  (1..*).grep(
    {
      $/ = $_; # copy the input ($_) to $/
      map { # map used just for side effect
        ->{
          $/ % $_    # if $/ is divisible by the current fib factor
        ||
          ($/ /= $_) # divide it out once
        ;
          # return the current value in $/
          $/
        }
        ... # repeat until that returns:
        * !%% $_ # something that is not divisible by the current fib factor
        ;0
      },
      # the possible fibonacci factors plus one, reversed
      # ( the extra is to save one byte )
      reverse 2,3,&[+] ... *>$_;

      # is the end result of factoring equal to 1
      # ( for the grep above )
      2 > $/
    }
  )[ $_ ] # get the value at 0-based index
}

2

Python 3、175 170 148バイト

-22バイトの@Dennisに感謝

j=x=int(input())
y=1,1
exec('y+=y[-2]+y[-1],;'*x)
i=c=0
while c<x:
    if j>=x:j=0;i+=1;t=i
    if t%y[~j]<1:t/=y[~j];j-=1
    if t<2:c+=1;j=x
    j+=1
print(i)

STDINから入力を受け取り、STDOUTに出力します。これは1つのインデックスです。100番目の項の計算には、およそ10分の1秒かかります。

使い方

j=x=int(input())                Get term number x from STDIN and set Fibonacci number index
                                j to x to force initialisation of j later 
y=1,1                           Initialise tuple y with start values for Fibonacci sequence
exec('y+=y[-2]+y[-1],;'*x)      Compute the Fibonacci sequence to x terms and store in y
i=c=0                           Initialise test number i and term counter c
while c<x:                      Loop until x th term is calculated
    if j>=x:j=0;i+=1;t=i        Initialise Fibonacci number index j, increment i and
                                initialise temp variable t for looping through all j for
                                some i. Executes during the first pass of the loop since
                                at this point, j=x
    if t%y[~j]<1:t/=y[~j];j-=1  Find t mod the j th largest Fibonacci number in y and if no
                                remainder, update t by dividing by this number.
                                Decrementing j means that after a later increment, no
                                change to j occurs, allowing for numbers that are 
                                divisible by the same Fibonacci number more than once by
                                testing again with the same j
    if t<2:c+=1;j=x             If repeated division by ever-smaller Fibonacci numbers
                                leaves 1, i must be a Fibonacci product and c is
                                incremented. Setting j equal to x causes j to be reset
                                to 0 during the next loop execution
    j+=1                        Increment j
print(i)                        i must now be the x th Fibonacci product. Print i to STDOUT

Ideoneでお試しください


2

パイソン2、120の 107バイト

g=lambda k:1/k+any(k%i==0<g(k/i)for i in F)
F=2,3;k=0;n=input()
while n:F+=F[k]+F[-1],;k+=1;n-=g(k)
print k

Ideoneでテストします。

使い方

Fをタプル(2、3)(最初の2つのフィボナッチ数が1より大きい)、k0nをSTDINから読み取った整数として初期化します。

一方で、nが正である、我々は次の操作を行います。

  • F [k] + F [-1]として計算された次のフィボナッチ数、つまりFの最後の2つの要素の合計をタプルFに追加します。

  • kをインクリメントします。

  • nからg(k)を引きます。

gは、kがフィボナッチ数の積である場合にのみ1を返すため、n0に達すると、kn 番目のフィボナッチ数であり、STDOUTに出力します。

gは次の目的を達成します。

  • k1の場合、フィボナッチ数の積であり1/k、必ず1を返します。

  • k1より大きい場合、Fのg(k/i)すべてのフィボナッチ数iに対して再帰的に呼び出します。

    g(k/i)k / iがフィボナッチ数積であるかどうかを再帰的にテストします。1g(k/i)返し、ikを均等に分割する場合、k%i = 0で条件が成立するため、kはフィボナッチ数とフィボナッチ数の積であるようなフィボナッチ数がある場合に限り、g1を返します。k%i<g(k/i)


1

JavaScript(ES6)、136

私のPCで約100秒で用語100を計算し、かなりゆっくりとゴルフをしました。

(n,F=i=>i>1?F(i-1)+F(i-2):i+1,K=(n,i=1,d,x)=>eval('for(;(d=F(i++))<=n&&!(x=!(n%d)&&K(n/d)););x||n<2'))=>eval('for(a=0;n;)K(++a)&&--n;a')

ゴルフの回数が減り、速度も速くなります(回避eval

n=>{
  F=i=> i>1 ? F(i-1)+F(i-2) : i+1; // recursive calc Fibonacci number
  K=(n,i=1,d,x)=>{ // recursive check divisibility
    for(; (d=F(i++))<=n && !(x=!(n%d)&&K(n/d)); );
    return x||n<2
  };
  for(a=0; n; )
    K(++a) && --n;
  return a
}

テスト

X=(n,F=i=>i>1?F(i-1)+F(i-2):i+1,K=(n,i=1,d,x)=>eval('for(;(d=F(i++))<=n&&!(x=!(n%d)&&K(n/d)););x||n<2'))=>eval('for(a=0;n;)K(++a)&&--n;a')

function test() {
  var i=+I.value
  O.textContent=X(i)
}

test()
<input id=I value=100 >
<button onclick="test()">Go</button><pre id=O></pre>


1

Haskell、123バイト

f=2:scanl(+)3f
m((a:b):c)=a:m(b?(a#c))
v#((a:b):c)|v==a=b?(v#c)
_#l=l
y?(z:e)|y>z=z:y?e
a?b=a:b
l=1:m[[a*b|b<-l]|a<-f]
(l!!)

非常に怠zyで、無限大です!

恐らく短絡法ではないかもしれませんが、ハミング数のリストを計算する非常によく知られた方法の一般化であるこのアプローチを試さなければなりませんでした。f2から始まるフィボナッチ数のリストです。簡潔にするために、lol(リストのリスト)は、最初の要素で順序付けられた無限リストの無限リストであるとしましょう。mLOLをマージして重複を削除する関数です。2つの中置ヘルパー関数を使用します。?無限にソートされたリストをlolに挿入します。#最初のリストの先頭として表示されるlolから値を削除し、残りのリストをで再挿入し?ます。

最後に、lフィボナッチ数の積である数のリストがあります。これは、1の後にlフィボナッチ数を乗算して得られたすべてのリストをマージしたものとして定義されます。最後の行は、!!リストにインデックス付けするために必要な関数(名前にバインドせずにそのままコピーしないでください)を示しています。これにより、関数のインデックスが0になります。

100番目または100,000番目の数値の計算に問題はありません。



0

パイソン2、129の 128 125 123 121バイト

g=lambda k:1/k|any(abs(round(5**.5*i)**2-5*i*i)==4>k%i<g(k/i)for i in range(k+1))
f=lambda n,k=1:n and f(n-g(k),k+1)or~-k

Ideoneでテストします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.