Python
 Computer >> コンピューター >  >> プログラミング >> Python

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 が大きくなっても現実的な時間で処理できます。

  1. 【初心者向け】Pythonのissuperset()メソッドの使い方をわかりやすく解説

    はじめにこの記事では、Pythonのissuperset()メソッドについて、基本的な仕組みから実際のコード例まで詳しく解説します。issuperset()は、セット(集合)に対して使用できるメソッドで、引数として渡されたセットのすべての要素が、呼び出し元のセットに含まれているかどうかを判定します。呼び出し元のセットBが、引数のセットAのすべての要素を含んでいる場合 → True を返すセットAの要素がすべてBに含まれていない場合 → False を返すつまり、「BがAの上位集合(スーパーセット)であるかどうか」を判定するためのメソッドです。基本構文B.issuperset(A)この式は、Bが

  2. Pythonのcalendarモジュールでカレンダーを自由に操作する方法

    Pythonには、カレンダーや日付に関する処理をまとめて扱うための標準モジュール calendar が用意されています。このモジュールには豊富な組み込み関数が含まれており、年間カレンダーの表示から特定月の取得、月の日数計算、うるう年の判定まで、さまざまな処理を簡単なコードで実現できます。ここでは、calendar モジュールの代表的な使い方を具体例とともに解説します。1年分のカレンダーを表示するcalendar.calendar(年) を使うと、指定した年の1年分のカレンダー全体をテキスト形式で出力できます。サンプルコードimport calendar print(calendar.calen