【C++】Dで割り切れるN桁の数を見つけるアルゴリズム
2つの整数 N と D が与えられたとき、D で割り切れる N 桁の数を見つける問題を考えます。例えば、N = 3、D = 5 の場合、答えは 500 になります。一見難しそうに思えるこの問題ですが、実はとてもシンプルな発想で解決できます。
解法のアイデア
基本となる考え方は、「D を先頭に置き、その後ろに 0 を付け足して N 桁にする」というものです。D の桁数を m とすると、D の末尾に (N − m) 個の 0 を連結した数は、全体でちょうど N 桁となり、必ず D で割り切れます。これは、作成される数が D × 10(N−m) に相当し、10 のべき乗を掛けても D で割り切れるという性質が保たれるためです。
ただし、例外がひとつあります。D が 10 以上で、かつ N が 1 の場合です。このとき、1 桁の数で D を割り切ることはできないため、条件を満たす数は存在しません。プログラムではこのケースを検出し、「数が見つからない」旨を返すようにします。
アルゴリズムの手順
- D を文字列に変換し、その桁数 m を取得する。
- D ≥ 10 かつ N = 1 の場合は解が存在しないため、エラーメッセージを返す。
- それ以外の場合は、D の文字列の末尾に (N − m) 個の '0' を追加する。
- 完成した文字列を結果として返す。
C++での実装例
#include<iostream>
using namespace std;
// D で割り切れる N 桁の数を文字列として生成する関数
string nDigitDivByD(int n, int d) {
string ans = "";
if (d < 10) { // D が 1 桁の場合
ans += to_string(d);
for (int i = 1; i < n; i++)
ans += "0";
} else { // D が 2 桁以上の場合
if (n == 1)
return "Cannot find any number"; // 解が存在しない
else {
string temp = to_string(d); // D の桁数を取得
ans += to_string(d);
for (int i = 0; i < n - temp.length(); i++)
ans += "0";
}
}
return ans;
}
int main() {
int n = 5, d = 15;
cout << nDigitDivByD(n, d);
}出力
15000
この例では N = 5、D = 15 が与えられているため、15 の末尾に 3 個の 0 を付けた 15000 が出力されます。15000 は確かに 5 桁であり、15 で割り切れる数になっています。
計算量について
このアルゴリズムは文字列の構築が中心の処理となるため、時間計算量は O(N)、使用するメモリも O(N) で済みます。桁数が大きくなっても線形時間で処理できるため、非常に効率的な解法と言えます。
-
C++で3で割り切れるが6で割り切れない数nの順列を求める方法
問題の概要ある数nが与えられたとき、その桁を並べ替えた順列の中から「3で割り切れるが、6では割り切れない」数を見つけることを考えます。そのような値を作ることができない場合は、-1を返します。例えば、nが336の場合、答えの候補として363が出力されます。解法の考え方ご存知の通り、6で割り切れる数とは、3と2の両方で割り切れる数のことです。つまり、3で割り切れる偶数は必ず6でも割り切れます。そこで、3で割り切れかつ偶数である数の桁を入れ替えて奇数にすることができれば、その数が求める答えとなります。ここで重要なポイントとして、桁を並べ替えても各位の数字の合計は変わらないため、元の数が3で割り切れれ
-
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 が含まれているかを