この関数を分析する上での主な課題は、再帰呼び出しがそれほど多くないことですが、各呼び出しは徐々に大きくなる要素のリストを返します。特に、n! があることに注意してください。n 要素のリストの順列。したがって、サイズ n のリストに対して再帰呼び出しを行うと、n 個になることがわかります。要素が返されました。
それでは、これがランタイムにどのように影響するかを見てみましょう。要素が 1 つだけのリストがある場合、時間計算量は O(1) です。それ以外の場合は、リストに n + 1 個の要素があるとします。そのときのアルゴリズム
- サイズ n のリストに対して再帰呼び出しを行います。
- 返された要素ごとに、可能なすべての位置でリストの最初の要素をスプライスします。
- 結果を返します。
再帰の各レベルで行われた作業を見るだけで、再帰の合計実行時間を分析できます。つまり、ここではステップ (2) と (3) に焦点を当てます。
ステップ 2 で、リストに n + 1 個の要素がある場合、n を見なければならないことに注意してください。再帰呼び出しによって生成された順列。これらの各順列には n 個の要素があります。順列ごとに、n + 1 個の新しいリストを作成します。それぞれのリストには n + 1 個の要素が含まれます。したがって、n! ループ反復、それぞれが (n + 1) 2の作業を行います。したがって、このレベルで行われる総作業量は (おおよそ) (n + 1) 2 · n!です。(n + 1) · n! = (n + 1)! なので、行われた作業は (n + 1)(n + 1)! と書くことができます。これは厳密には (n + 2)! よりも小さいため、合計要素数が n + 1 の場合に行われる作業は O((n + 2)!) であると言えます。(n! = o((n + 2)!) であるため、これが O(n!) であるとは言えないことに注意してください)。
これで、完了した作業の合計は (大まかに言えば) によって与えられると言えます。
1!+2!+3!+ ... + (n + 1)!
私の知る限り、これには適切な閉じた形式の式はありません。ただし、次のことに注意してください。
1!+2!+3!+ ... + (n + 1)!
< (n + 1)! + (n + 1)! + ... + (n + 1)!
= (n + 2)(n + 1)!
= (n + 2)!
したがって、全体の式は O((n + 2)!) です。同様に、
1!+2!+3!+ ... + (n + 1)!
> (n + 1)!
したがって、全体の式は Ω((n + 1)!) です。つまり、真の答えは (n + 1) の間のどこかに (漸近的に) はさまれています! そして (n + 2)!. したがって、実行時間は階乗的に高速に増加します。
お役に立てれば!