C++で素数の数字(2・3・5・7)のみで構成されるn番目の数を効率的に求める方法
この記事では、整数Nが与えられたときに、「素数の数字(2、3、5、7)のみで構成される数列」のN番目の数を求めるアルゴリズムを解説します。
素数の数字だけで構成される数列は、次のように並びます。
2, 3, 5, 7, 22, 23, 25, 27, 32, 33, ...
問題を理解するための例
入力:N = 6 出力:23
この場合、数列の6番目の要素は「23」となるため、出力は23です。
解法のアプローチ
この問題を解くシンプルな方法は、数列の規則性を観察することです。まず、与えられたインデックスNに対応する項を見つけることを考えます。
使用できる数字が4種類(2、3、5、7)しかないため、この数列は「4進法の数体系」として扱うことができます。つまり、長さxの数は全部で4x個存在します。
具体的な手順は以下の通りです。
- まず、N番目の数が何桁の数に属するかを特定します。各桁数ごとの個数(4、16、64...)を累積していき、Nがどの範囲に入るかを調べます。
- 次に、その桁数の中でN番目に相当する位置を計算し、対応する数字(2、3、5、7)を1桁ずつ決定していきます。
- 最後に、決定した桁を連結して答えを出力します。
C++での実装例
以下は、上記のアプローチを実装したC++プログラムです。
#include <iostream>
#include <math.h>
using namespace std;
void findNthNumber(int n){
long x = 1;
long lastNum = 0;
while (true) {
long currNum = lastNum + pow(4, x);
if (lastNum < n && currNum >= n)
break;
x++;
lastNum = currNum;
}
for (int i = 1; i <= x; i++) {
for (long j = 1; j <= 4; j++) {
if (lastNum + pow(4, x - i) < n)
lastNum += pow(4, x - i);
else {
if (j == 1)
cout<<"2";
else if (j == 2)
cout<<"3";
else if (j == 3)
cout<<"5";
else if (j == 4)
cout<<"7";
break;
}
}
}
}
int main(){
int N = 32;
cout<<N<<"番目の素数数字のみの数は ";
findNthNumber(N);
return 0;
}
実行結果
32番目の素数数字のみの数は 257
まとめ
このように、素数の数字のみで構成される数列は4進法と同じ構造を持っているため、各桁の個数を累積的に調べることで、N番目の数を効率よく求めることができます。全ての数を生成して数え上げる方法(総当たり)に比べ、計算量を大幅に抑えられるのがこの手法の大きな利点です。
-
C++で数値とその最大素因数の合計を求める方法
はじめに正の整数 n が与えられたとき、「n そのもの」と「n の最大素因数」の合計を求める問題を考えてみましょう。例えば、数が 26 の場合、26 を素因数分解すると 2 × 13 となるため、最大素因数は 13 です。したがって、求める合計は 26 + 13 = 39 となります。アルゴリズムの考え方アプローチはとてもシンプルです。対象の数を素因数分解し、最大の素因数を見つける元の数と最大素因数を足し合わせる結果を返す最大素因数の効率的な求め方すべての約数を総当たりで調べると非効率ですが、以下の手順に従えば O(√n) 程度の計算量で最大素因数を求められます。まず、数が 2 で割り切れる間
-
C++で1からnまでの「0」と「1」のみを含む整数の個数を求める方法
問題の概要ある数値 n が与えられたとき、1からnまでの整数の中に、「0」と「1」のみで構成される数がいくつあるかを求めることを考えます。例えば、n = 15 の場合、条件を満たすのは「1」「10」「11」の3つであるため、答えは3となります。解法のアプローチこの問題は、再帰関数を使って「0」と「1」だけで作れる整数を順番に生成していくことで、効率的に解くことができます。現在の値 p に対して、末尾に「0」を追加した値(p × 10)と、末尾に「1」を追加した値(p × 10 + 1)の2方向へ再帰的に探索を進め、p が n を超えた時点で探索を打ち切るのがポイントです。C++での実装例#in