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

Pythonで長さkの増加部分列の個数を動的計画法で求める方法

数値のリスト nums と整数 k が与えられたとき、「厳密に増加する」サイズ k の部分列(サブシーケンス)が何個存在するかを求めます。答えが非常に大きくなる可能性があるため、10^9 + 7 で割った余りを返します。

たとえば、nums = [2, 3, 4, 1]k = 2 の場合、出力は 3 になります。これは、サイズ 2 の増加部分列として [2, 3]、[3, 4]、[2, 4] の 3 つが存在するためです。

解法のアプローチ

この問題は動的計画法(DP)を用いて効率的に解くことができます。dp[j] は「インデックス j の要素を末尾とする、現在の長さの増加部分列の個数」を表し、各イテレーションで部分列を 1 要素ずつ伸ばしていきます。手順は以下の通りです。

  • m := 10^9 + 7(剰余演算用の定数)
  • dp := nums と同じサイズのリストを作成し、すべて 1 で初期化
  • 次の処理を k 回繰り返す:
    • j を dp のサイズ - 1 から 0 まで 1 ずつ減らしながら繰り返す:
      • dp[j] := 0
      • i を 0 から j - 1 まで繰り返す:
        • nums[i] < nums[j] の場合、dp[j] := dp[j] + dp[i]
  • dp の全要素の合計を m で割った余りを返す

Pythonでの実装例

理解を深めるために、以下の実装を見てみましょう。

class Solution:
    def solve(self, nums, k):
        m = 10 ** 9 + 7
        dp = [1] * len(nums)
        for _ in range(k - 1):
            for j in range(len(dp) - 1, -1, -1):
                dp[j] = 0
                for i in range(j):
                    if nums[i] < nums[j]:
                        dp[j] += dp[i]
        return sum(dp) % m

ob = Solution()
nums = [2, 3, 4, 1]
k = 2
print(ob.solve(nums, k))

入力

[2, 3, 4, 1], 2

出力

3

計算量について

このアルゴリズムの時間計算量は O(k × n²)(n はリストの長さ)、空間計算量は O(n) です。n や k が大きい場合は、Binary Indexed Tree(BIT)などのデータ構造を使うことでさらに高速化することも可能です。

  1. Pythonで二分探索木(BST)の指定範囲内にあるノード数を求める方法

    問題の概要 二分探索木(BST)が与えられ、さらに左側の境界値 l と右側の境界値 r が指定されます。このとき、木に含まれるすべてのノードの中で、値が l 以上 r 以下の範囲内にあるノードの個数を求めるのが目的です。 例えば、次のような木が与えられたとします。 このとき l = 7、r = 13 とすると、範囲内に含まれるノードは 8、10、12 の3つなので、出力は 3 になります。 アルゴリズムの考え方 スタックを使った反復的な深さ優先探索(DFS)で木をたどります。重要なポイントは、二分探索木の性質を活かして枝刈り(pruning)を行うことです。値が境界より小さいノードの左側の

  2. Pythonでリスト内の最大値を見つける方法|sort()とmax()の2つのアプローチ

    この記事では、リストの中から最大の数値を見つけるための解決策とアプローチについて詳しく解説します。問題の概要数値のリストが与えられたとき、その中から最大の要素を見つけ出す必要があります。Pythonでは、主に以下の2つの方法でこれを実現できます。ソート(並べ替え)を利用する方法組み込み関数 max() を利用する方法アプローチ1:sort() 関数を使う方法リストを sort() メソッドで昇順に並べ替えると、リストの最後の要素(インデックス -1)が必ず最大値になります。サンプルコードlist1 = [18, 65, 78, 89, 90] list1.sort() # メイン処理 prin