階乗関連のアルゴリズムとその C++ 実装

階乗関連のアルゴリズムとその C++ 実装

階乗とは、必要な数値が得られるまで 1 × 2 × 3 × 4 を掛け合わせることを意味します。 C++の階乗についても同様です。階乗アルゴリズムに関連する側面は 2 つあります。1 つは高精度の計算であり、もう 1 つは数論に関連しています。

1つ。 高精度で階乗を計算する

これは実際には最も技術的な問題ではありませんが、頻繁に使用されるため、記述して最適化する必要があります。

まず、12 以下の階乗計算を見てみましょう (計算結果は 32 ビットの範囲を超えません)。

  1. int 階乗(int n) {
  2. ( n == 1 || n == 0)の場合
  3. 1 を返します。
  4. 階乗(n-1)*nを返します。
  5. }
  6.  

この再帰プログラムはシンプルで明確であり、非常に直感的です。ただし、n > 12 になると、32 ビット int 型の範囲を超え、誤った結果が発生します。したがって、上記の再帰プログラムは、n <= 12 の階乗計算にのみ適しています。より大きな n の階乗を計算するには、階乗計算に高精度の乗算アルゴリズムを組み込む必要があります。高精度の乗算プロセスは、次のように簡単に説明できます。(ここで、A * B = C、A[0]、B[0]、C[0] はそれぞれ長さを格納します)

  1. ( i = 1 ; i < = A[0]; i++)の場合
  2. ( j = 1 ; j < = B[0]; j++) の場合 {
  3. C[i+j-1] += A[i]*B[j]; // 現在の i+j-1 に対応する項目 + A[i] * B[j]
  4. C[i+j] += C[i+j-1]/10; // 次の桁 + 商(繰り上がり)
  5. C[i+j-1] %= 10; // 余りとして計算できる
  6. }
  7. C[0] = A[0] + B[0];
  8. while (C[0] > 1 && C[C[0]] == 0) C[0]--; // 先頭の0を削除してCの実際の長さを取得します

この高精度の乗算により、階乗の計算は単純に繰り返し実行できます。

(i = 2; i <= n; i++) の場合 {

i を文字配列に変換します。

高精度の乗算を実行します。前の結果にiを掛けます。

}

二。 数論に関連する

階乗がどんどん大きくなるにつれて、数論を巧みに利用して興味深い数値 (値) を見つけることが階乗アルゴリズムの設計ポイントになります。関連する質問と分析をいくつか示します。

(1)階乗の最後のゼロでない桁を計算する。

これは古典的な問題です。より複雑なアルゴリズムでは難しい数式が使用されますが、残念ながらその使い方がわかりません。オンラインの資料から学び、次のようなシンプルでわかりやすいアルゴリズムを思いつきました。

n! を観察すると、乗算処理中に、任意の n > 1 について、n! の最後のゼロ以外の桁が偶数であることがわかります。最後のゼロ以外の数字のみを保持する必要があります。掛け算する数に 5 の因数が含まれている場合、5 の因数はすべて 8 として掛け算できます。その理由は次のとおりです。

…x2*5=…10(切り捨て)または…60、最後のゼロ以外の数字は6です。そして、2*8=16となり、最後の桁は6になります。

…x4*5=…70(切り捨て)または…20、最後のゼロ以外の数字は2です。そして、4*8=32となり、最後の桁は2になります。

…x6*5=…30(切り捨て)または…80、最後のゼロ以外の数字は8です。そして、6*8=48となり、最後の桁は8になります。

…x8*5=…90(切り捨て)または…40、最後のゼロ以外の数字は4です。そして、8*8=64となり、最後の桁は4になります。

(n > 1 の場合、最後の数字は 1、7、3、9 ではなく、常に 2、4、6、8 の周期で表示されます)

したがって、反復乗算を実行する場合、主なことは 5 の因数の数を計算することです。同時に、5 の因数の数は 4 の循環であることがわかります (つまり、その数を 4 で割った値のみを取得する必要があります)。次に、さまざまな状況での 5 の因数の数は、res[5][4] = {{0,0,0,0}, {2,6,8,4}, {4,2,6,8}, {6,8,4,2}, {8,4,2,6}} で取得でき、nonzero[i] は i の階乗の最後の桁を表すために使用されます。

t が偶数の場合は、直接乗算します: nonzero[i] = (nonzero[i-1]*t)%10。

それ以外の場合、nonzero[i] = res[((nonzero[i-1]*t)%10)/2][five];

ここで、t は 5 の因数をすべて除去した結果であり、five は 4 を法とする 5 の因数の数です。関連トピック:

http://acm.zju.edu.cn からの質問 1222。ただし、入力 n は 32 ビット int 値の範囲に限定されず、非常に長い長さを持つことに注意してください。したがって、この異常な問題を計算するときは、高精度の除算 (n/=5) と高精度の加算 (cnt+=n) を使用する必要があります。

(2) 階乗の最後にはゼロがいくつありますか?

分析により、因数 5 の数は実際には末尾の 0 の数であることが示され、因数 i を含む 1 から n までの数値の数を計算する簡単なアルゴリズムは次のようになります。

cnt = 0; while (n) { n /= i; cnt += n; }

したがって、i を 5 に置き換えるだけで、5 の因数の数、つまり n! の末尾のゼロの数を取得できます。

(3) 階乗の左側の2番目の数値を返します

シンプルなアルゴリズム: 実数を掛けて、100 を超える場合は 10 で割り、1 の位に切り上げます。整数部分の 1 桁目は階乗結果の左から 2 番目の桁であるためです。関連トピック:

(4) 値 m が n を割り切れるかどうかを判断します。

アルゴリズム: 素因数決定法を使用する

A. まず、2つの特殊なケースを直接出力します。

m == 0 の場合、0 は間違いなく n を割り切れません。

n >= m であれば、m は確実に n を割り切れます。

B. すると、m > n の 1 つのケースのみが残ります。m の最小の素因数から始めます。素因数を i とします。すると、m の素因数 i の数 nums1 がわかります。次に、閉区間 i と n の間の数値を調べて、それらに素因数 i がいくつ含まれているかを確認します。上記 (2) で紹介した数式を使用して、nums2 を計算することができます。 nums2 < nums1 の場合、1 ~ n の素因数の数 < 除数 m の素因数 i の数であることを意味し、m は n! を割り切れないはずなので、ok = false に設定します。

C. ***: !ok または m > n または m == 0 の場合、割り切れません。それ以外の場合は割り切れます。

(5)数 N はいくつかの異なる階乗の合計として表現できますか。

ここで選択できる階乗は、0! ~ 9! です。実際、この質問は数論とは何の関係もなく、検索に関するものです。関連する質問: http://acm.zju.edu.cn からの質問 2358。

分析: 選択できる階乗の数が少ないため、DFS 検索を直接使用できます。

A. まず、0から9までの階乗の表A[10]を作成し、次にその和を形成できる配列ans[N]を設定します。

B. 深さ優先探索法:

  1. 検索(n) {
  2. ( i = n ; i < = 9; i++) の場合 {
  3. sum += A[i]; //合計。ans配列にsumが存在しない場合は、ans[]配列にsumを挿入します。
  4. 検索(n+1);
  5. sum - = A [i]; // バックトラック
  6. }
  7. }

C. ***入力 n について、ans 配列に n が存在するかどうかを確認します。存在する場合は、n を異なる階乗和として表現できることを意味し、存在しない場合は表現できません。

上記の紹介から、C++ の階乗はループ ステートメントを使用して実装されていることがわかります。実際、階乗アルゴリズムを習得すれば、どの言語でも簡単に実装できます。これが階乗についてのより深い理解に役立つことを願っています。

【編集者のおすすめ】

  1. 2.2 階乗に怯まないで
  2. Java でアルゴリズムを実装する場合は、再帰に注意してください。
  3. 非反復乱数列生成アルゴリズム
  4. C/C++アルゴリズム設計における任意のビット幅の使用

<<:  「スペースを時間で交換する」アルゴリズムはキャッシュの世界へとあなたを導きます

>>:  コンシステントハッシュアルゴリズムの詳細な説明

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

人工知能は目覚めたのか?アマゾンの人工知能は人間の命令を聞かず不気味な笑い声を上げる

人類が人工知能の開発に熱心に取り組み始めて以来、著名な科学者ホーキング博士をはじめ、疑問や反対の声が...

中国人工知能産業発展連盟メディアプロジェクトグループが設立され、51CTOは連盟の最初の専門メディアの1つになりました。

中国人工知能産業発展連盟メディアプロジェクトグループの設立会議が2018年1月25日に北京で開催され...

知湖橋プラットフォームにおける大型モデルの応用と実践

1. 事業の状況及び背景まずはブリッジプラットフォームを紹介します。 Bridge は、Zhihu ...

...

ジョン・マカフィーの意見: 人工知能は人類を滅ぼすのか?

2017 年 3 月 9 日、ハッカー アンダーグラウンド テクノロジーの専門家であり作家でもある...

役に立つヒント | 複数の事前トレーニング済みビジョンモデルの転移学習

この記事では、Keras Tensorflow 抽象ライブラリに基づく転移学習アルゴリズム モデルを...

マルチモーダル世界モデルで未来を予測!カリフォルニア大学バークレー校の新しいAIエージェントは人間の言語を正確に理解し、SOTAを刷新する

現在、強化学習ベースのエージェントは、「青いレンガを拾う」などの指示を簡単に実行できます。しかし、ほ...

...

...

機械学習は 5G ネットワークにどのように役立ちますか?

機械学習機械学習は、コンピューティング システムの能力の向上とデータの可用性の向上により、過去 10...

反論: AIに急いで取り組むべきではない5つの理由

[51CTO.com クイック翻訳] 今日、人工知能はもはやSFの中の漠然とした概念ではなく、私たち...

「アルゴリズムの構成」は「ブラックボックス」を明らかにする:アルゴリズムは数学に関するものだが、人間に関するものである

アルゴリズムは私たちの生活の中でますます一般的なものになってきています。しかし、アルゴリズムに関する...

トイレ掃除から純資産435億ドルへ!黄仁訓の成功の秘訣:時計を着けないこと

若者に向けて、Lao Huang 氏から 3 つの提案を紹介します。学ぶことをやめず、できる限り最善...

...