Pythonで解く「強力な整数」問題:x^i + y^j の全組み合わせを効率的に列挙する
「強力な整数」とは何か
正の整数 x と y が与えられたとき、ある整数 n が n = xi + yj(i ≥ 0、j ≥ 0)の形で表せるとき、n を強力な整数(Powerful Integer)と呼びます。この記事では、bound 以下の値をもつ強力な整数をすべて列挙するアルゴリズムを、Python の実装例とともに分かりやすく解説します。
たとえば x = 2、y = 3、bound = 10 という入力に対しては、出力は [2, 3, 4, 5, 7, 9, 10] になります。それぞれの値は次のように構成されています。
- 2 = 20 + 30
- 3 = 21 + 30
- 4 = 20 + 31
- 5 = 21 + 31
- 7 = 22 + 31
- 9 = 23 + 30
- 10 = 20 + 32
解き方のアプローチ
基本となる考え方はシンプルで、xi を外側のループで固定し、内側のループで yj を順に増やしながら全探索するというものです。同じ値が異なる (i, j) の組から生まれることがあるため、結果は重複を自動的に排除できる集合(set)に格納します。
実装上の注意点は、x または y が 1 のケースです。1 のべき乗は常に 1 なので、そのままループを回すと無限ループに陥ってしまいます。そこで、該当する変数が 1 の場合には 1 回だけ計算してループを抜けるようにすれば、すべてのケースを統一的に扱えます。
Pythonでの実装例
class Solution:
def powerfulIntegers(self, x, y, bound):
res = set()
i = 0
# y^j の最小値は 1 なので、x^i + 1 が bound を超えたら探索終了
while x ** i + 1 <= bound:
j = 0
# y^j を増やしながら条件を満たす値を記録
while x ** i + y ** j <= bound:
res.add(x ** i + y ** j)
j += 1
if y == 1: # y = 1 のときは無限ループを防止
break
i += 1
if x == 1: # x = 1 のときは無限ループを防止
break
return sorted(res)
ob = Solution()
print(ob.powerfulIntegers(2, 3, 10))
入力と出力
入力
x = 2, y = 3, bound = 10
出力
[2, 3, 4, 5, 7, 9, 10]
動作のポイント
- ループ終了条件:yj の最小値は 1(j = 0 のとき)なので、xi + 1 が bound を超えた時点で、それ以上 xi を大きくしても答えは見つかりません。
- 重複の除去:たとえば 5 = 21 + 31 = 22 + 30 のように、同じ値が複数の組み合わせから現れるため、set による重複管理が有効です。
- 境界ケース:x = 1 かつ y = 1 の場合は候補が 2 のみとなり、bound ≥ 2 のときだけ [2] を返します。
計算量
xk ≤ bound となる最大の k を K、ym ≤ bound となる最大の m を M とすると、調べる必要がある組み合わせは多くても (K + 1) × (M + 1) 個です。K ≒ log(bound) / log(x)、M ≒ log(bound) / log(y) であり、べき乗の増加は非常に速いため、bound が大きくなっても現実的な時間で処理できます。
-
【初心者向け】Pythonのissuperset()メソッドの使い方をわかりやすく解説
はじめにこの記事では、Pythonのissuperset()メソッドについて、基本的な仕組みから実際のコード例まで詳しく解説します。issuperset()は、セット(集合)に対して使用できるメソッドで、引数として渡されたセットのすべての要素が、呼び出し元のセットに含まれているかどうかを判定します。呼び出し元のセットBが、引数のセットAのすべての要素を含んでいる場合 → True を返すセットAの要素がすべてBに含まれていない場合 → False を返すつまり、「BがAの上位集合(スーパーセット)であるかどうか」を判定するためのメソッドです。基本構文B.issuperset(A)この式は、Bが
-
Pythonのcalendarモジュールでカレンダーを自由に操作する方法
Pythonには、カレンダーや日付に関する処理をまとめて扱うための標準モジュール calendar が用意されています。このモジュールには豊富な組み込み関数が含まれており、年間カレンダーの表示から特定月の取得、月の日数計算、うるう年の判定まで、さまざまな処理を簡単なコードで実現できます。ここでは、calendar モジュールの代表的な使い方を具体例とともに解説します。1年分のカレンダーを表示するcalendar.calendar(年) を使うと、指定した年の1年分のカレンダー全体をテキスト形式で出力できます。サンプルコードimport calendar print(calendar.calen