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

Pythonで合計が0となる最長の部分リストの長さを求める方法

問題概要

1と−1という2つの値だけを含むリストが与えられたとき、要素の合計が0になる最長の部分リスト(連続する部分列)の長さを求めます。

例えば、入力が nums = [1, 1, -1, 1, 1, -1, 1, -1, 1, -1] の場合、出力は 8 になります。これは、最長の部分リストが [-1, 1, 1, -1, 1, -1, 1, -1] であり、その合計が0だからです。

解法のアプローチ:累積和と辞書

この問題は「累積和(プレフィックスサム)」を使うことで効率的に解けます。ある位置 i までの累積和が cs であるとき、同じ累積和の値が以前に位置 j で現れていれば、区間 j+1 〜 i の合計は必ず0になります。そこで、各累積和が最初に出現したインデックスを辞書に記録しておき、同じ値が再び現れたときにその距離を計算するのがポイントです。

アルゴリズムの手順

  • table := 新しい空の辞書(各累積和が最初に現れたインデックスを記録)
  • cs := 0(現在の累積和)、max_diff := 0(答えとなる最大長)
  • i を 0 から nums のサイズ − 1 まで繰り返す:
    • cs := cs + nums[i]
    • cs が 0 なら、先頭から i までの全体の合計が0なので、max_diff := max(i + 1, max_diff)
    • cs が table に存在するなら、max_diff := max(max_diff, i − table[cs])
    • そうでなければ、table[cs] := i
  • max_diff を返す

実装例

class Solution:
    def solve(self, nums):
        table = {}
        cs = 0
        max_diff = 0
        for i in range(len(nums)):
            cs += nums[i]
            if cs == 0:
                max_diff = max(i + 1, max_diff)
            if cs in table:
                max_diff = max(max_diff, i - table[cs])
            else:
                table[cs] = i
        return max_diff

ob = Solution()
nums = [1, 1, -1, 1, 1, -1, 1, -1, 1, -1]
print(ob.solve(nums))

入力

[1, 1, -1, 1, 1, -1, 1, -1, 1, -1]

出力

8

動作の解説

このコードでは、リストを左から順に走査しながら累積和 cs を更新していきます。累積和が0になった時点で、先頭からの部分リスト全体の合計が0であることが分かります。また、同じ累積和が2回現れた場合は、その2つの位置の間にある要素の合計が必ず0になるため、その間隔が答えの候補となります。辞書には各累積和の最初の出現位置だけを保存するので、常に最大の長さを正しく求められます。

計算量

時間計算量は O(n)、空間計算量も O(n) です。すべての要素を一度だけ走査し、辞書への挿入・参照は平均 O(1) で行えるため、総当たり的な O(n²) の解法と比べて非常に効率的です。

  1. Pythonで最長アナグラム部分列の長さを求めるプログラム

    問題の概要小文字のみで構成された2つの文字列 S と T が与えられたとき、「最も長いアナグラム部分列」の長さを求めます。ここでアナグラム部分列とは、両方の文字列に共通して含まれる文字を組み合わせて作れる、同じ文字構成を持つ部分列のことです。例えば、S = helloworld、T = hellorld の場合、答えは 8 になります。これは、両方の文字列で共有できる文字(h ×1、e ×1、l ×3、o ×1、r ×1、d ×1)の合計が8文字であるためです。解法のアプローチこの問題は、各文字列における文字の出現回数を数え、その最小値を合計することで効率的に解けます。手順は以下の通りです。文

  2. Pythonで最長のバランス括弧部分列の長さを求めるプログラム

    問題概要 文字列 s が与えられます。この文字列には括弧「(」と「)」が含まれており、その中からバランスの取れた(対応関係が成立している)括弧の部分列として最も長いものを見つけ、その長さを返すことが目標です。 たとえば、入力が s = ())(()( の場合、出力は 4 になります。「(」と「)」を選び抜いて ()() というバランスの取れた部分列を作れるためです。 解法のアプローチ この問題は、文字列を後ろから走査することで線形時間で解けます。閉じ括弧を先に確保しておき、開き括弧が出てきたときに対を成立させるという発想です。手順は以下の通りです。 結果を格納する変数 res を 0 で初