C++で解く「簡約分数」問題:0と1の間のすべての既約分数を求める方法
整数 n が与えられたとき、0より大きく1より小さい範囲に存在するすべての簡約済み(既約)分数を、分母が n 以下という条件で求めてリストとして返すことを考えます。分数の出力順序は問われません。
例えば、入力が n = 4 の場合、出力は ["1/2", "1/3", "1/4", "2/3", "3/4"] となります。"2/4" は "1/2" に約分できるため、簡約分数としては含まれません。
解法のアプローチ
この問題は以下の手順で解くことができます。
結果を格納する配列 ret を定義します。
i を分母として、i = 2 から n まで繰り返します。
j を分子として、j = 1 から i - 1 まで繰り返します。
c := i と j の最大公約数(GCD)を求めます。
a := j / c(約分後の分子)
b := i / c(約分後の分母)
文字列に変換した a と b を "/" で連結し、ret の末尾に追加します。
ret 内の一意な要素のみからなる配列を返します。
最大公約数を使って各分数を約分することで、重複する分数(例えば "2/4" と "1/2")が同じ文字列になり、最後に set で一意化することで簡約分数だけが残る仕組みです。
実装例
理解を深めるために、以下のC++による実装を見てみましょう。
#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<string> v){
cout << "[";
for(int i = 0; i<v.size(); i++){
cout << v[i] << ", ";
}
cout << "]"<<endl;
}
class Solution {
public:
vector<string> simplifiedFractions(int n) {
vector<string> ret;
for (int i = 2; i <= n; i++) {
for (int j = 1; j < i; j++) {
int c = __gcd(i, j);
int a = j / c;
int b = i / c;
ret.push_back(to_string(a) + "/" + to_string(b));
}
}
set<string> s(ret.begin(), ret.end());
return vector<string>(s.begin(), s.end());
}
};
main(){
Solution ob;
print_vector(ob.simplifiedFractions(4));
}入力
4
出力
[1/2, 1/3, 1/4, 2/3, 3/4]
計算量について
このアルゴリズムは二重ループを使用するため、時間計算量は O(n² × log n) となります(log n はGCD計算のコスト)。空間計算量は生成される分数の数に依存し、最大 O(n²) です。なお、set を使った一意化の代わりに「gcd(i, j) == 1」の場合のみ結果に追加する方法を採れば、約分処理と一意化処理を省略でき、より効率的な実装になります。
-
C++で質素数(Frugal Number)を判定する方法【サンプルコード付き】
この記事では、正の整数 N が与えられたときに、その数が質素数(Frugal Number)であるかどうかを判定するプログラムを C++ で作成する方法を解説します。 質素数とは? 質素数(FRUGAL NUMBER)とは、その数自身の桁数が、素因数分解による表現の桁数よりも厳密に大きい数のことです。 例:625 の場合 625 を素因数分解すると 54 となります。 625 自身の桁数:3 桁 54 の表現の桁数:2 桁 3 は 2 よりも厳密に大きいため、625 は質素数です。 最初のいくつかの質素数:125、128、243、256、343、512、625 など 問題を理解するための具
-
C++で五胞体数(ペンタトープ数)を求める方法
五胞体数とは? 五胞体数(ペンタトープ数)は、パスカルの三角形の第5の対角線上に現れる数列として知られています。この数列を定義するには、パスカルの三角形に少なくとも5つの数が必要となるため、数列の最初の数はパスカルの三角形の第4行である 1 4 6 4 1 から始まります。 本チュートリアルでは、n番目の五胞体数を求める方法を解説します。まずは具体的な例を見てみましょう。 入力 : 1出力 : 1入力 : 4出力 : 35 以下の図から出力を確認できます。 この問題は数列に関するものなので、解法ではまず数列のパターンを見つけることから始めます。 解法のアプローチ このプログラムでは、数列の