C++で1〜nの範囲にあるすべての数の約数の個数を求める方法
この問題では、整数Nが与えられ、1からnまでの範囲に含まれるすべての数について、それぞれの約数の個数を求めることが課題となります。
問題の例
具体例を見てみましょう。
入力 : N = 7
出力 : 1 2 2 3 2 4 2
N = 7の場合、1の約数は「1」の1個、2の約数は「1, 2」の2個、3の約数は「1, 3」の2個、4の約数は「1, 2, 4」の3個…というように、各数の約数の個数を順に出力します。
解法アプローチ1:各数ごとに約数を数える方法
最もシンプルな解法は、1からNまでの各数に対して、実際に割り切れる数を順番にカウントしていく方法です。各数iについて、2からiまでの値で順に割りを試し、余りが0になる回数を数えます。
サンプルコード1
#include <iostream>
using namespace std;
int countDivisor(int N){
int count = 1; // 1は必ず約数なので初期値を1とする
for(int i = 2; i <= N; i++){
if(N % i == 0)
count++;
}
return count;
}
int main(){
int N = 8;
cout<<"1から"<<N<<"までの各数の約数の個数 : ";
cout<<"1 ";
for(int i = 2; i <= N; i++){
cout<<countDivisor(i)<<" ";
}
return 0;
}
出力結果
1から8までの各数の約数の個数 : 1 2 2 3 2 4 2 4
この方法は直感的で理解しやすい反面、各数について約数の判定を行うため、計算量はO(N²)となり、Nが大きくなると処理時間が増加します。
解法アプローチ2:倍数を使った効率的な方法(ふるい法)
より効率的なアプローチとして、「エラトステネスのふるい」と似た考え方を利用する方法があります。
手順は以下の通りです。
- サイズ(N+1)の配列を作成し、すべての要素を1で初期化します(すべての数は少なくとも約数「1」を持つため)。
- iを2からNまで順に走査し、iの倍数にあたる配列の要素をすべてインクリメントします。
- 最終的に、配列の各要素にはその位置の数の約数の個数が格納されます。
この方法では、各約数がその倍数すべてに寄与するという性質を利用するため、計算量はO(N log N)程度に抑えられ、大幅な高速化が期待できます。
サンプルコード2
#include <iostream>
using namespace std;
void countDivisors(int N){
int arr[N+1];
// すべての要素を1で初期化
for(int i = 0; i <= N; i++)
arr[i] = 1;
// iの倍数すべてのカウントを増やす
for (int i = 2; i <= N; i++) {
for (int j = 1; j * i <= N; j++)
arr[i * j]++;
}
// 結果を出力
for (int i = 1; i <= N; i++)
cout<<arr[i]<<" ";
}
int main(){
int N = 8;
cout<<"1から"<<N<<"までの各数の約数の個数 : ";
countDivisors(N);
return 0;
}
出力結果
1から8までの各数の約数の個数 : 1 2 2 3 2 4 2 4
まとめ
1〜nの範囲のすべての数の約数の個数を求めるには、大きく分けて2つの方法があります。
- 単純な全探索: 各数ごとに約数を数える。実装は簡単だが、計算量はO(N²)。
- ふるい的な手法: 倍数ごとにカウントを増やす方式。計算量はO(N log N)程度で、大きなNでも高速に動作する。
競技プログラミングや大量のデータを扱う場面では、後者のふるい的なアプローチを採用することをおすすめします。
-
C++で指定した数字dを含む数値をすべて検索する方法
問題の概要数字 d と上限値 n が与えられたとき、0 から n までの範囲に存在する、数字 d を含むすべての数値を見つけることを考えます。例えば、n = 20、d = 3 の場合、該当する数値は [3, 13] の2つになります。また、n = 100、d = 3 の場合は、3、13、23、30〜39、43、53 といった具合に、3 が現れるすべての数値が該当します。解決のアプローチこの問題は、各数値を文字列に変換することでシンプルに解決できます。手順は以下のとおりです。1. 各数値を to_string() で文字列に変換する2. 変換した文字列の中に、対象の数字 d が含まれているかを
-
C++で配列内の数値の頻度(出現回数)を求める方法
配列に n 個の異なる要素が格納されているとします。この配列の中から、特定の要素が何回出現するか(頻度)を調べたい場合があります。例えば、配列 A = [5, 12, 26, 5, 3, 4, 15, 5, 8, 4] の中で「5」の頻度を調べると、答えは 3 になります。アルゴリズムの考え方この問題は、次の手順で解くことができます。1. 配列を左端から順に走査します。2. 現在の要素が調べたい数値と一致したら、カウンターを1つ増やします。3. 一致しない場合は、そのまま次の要素へ進みます。4. 配列の最後まで走査したら、カウンターの値が頻度となります。このアルゴリズムの計算量は O(n) で