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

Pythonで長さkの部分リスト反転により全要素を0にする最小操作回数を求めるプログラム

問題の概要

0と1のみで構成された数値のリスト nums と、整数 k が与えられます。

ここで、「長さkの部分リスト(サブリスト)を選んで反転する」という操作を考えます。反転を行うと、その範囲内のすべての1は0に、0は1に変わります。この操作を繰り返して、リスト内のすべての1を0にするために必要な最小の操作回数を求めてください。どのように操作してもすべてを0にできない場合は -1 を返します。

例えば、nums = [1,1,1,0,0,1,1,1]k = 3 の場合、出力は 2 になります。これは、先頭の3つの要素を反転して0にし、次に末尾の3つの要素を反転して0にできるためです。

解法のアプローチ

この問題は、以下の手順で解くことができます。

  • n := nums のサイズ
  • res := 0(操作回数のカウント)、flipped := 0(現在の反転状態)
  • to_conv := サイズnのリストを0で初期化(反転の影響が終わる位置を記録)
  • i を 0 から n-1 まで繰り返す:
    • flipped := flipped XOR to_conv[i]
    • cur := nums[i]
    • cur := cur XOR flipped
    • cur が 1 の場合:
      • flipped := flipped XOR 1
      • res := res + 1
      • i + k - 1 >= n の場合は -1 を返す(残りの範囲で反転できないため)
      • i + k < n の場合は to_conv[i + k] := 1 を設定
  • 最後に res を返す

アルゴリズムのポイント

このアルゴリズムの鍵となるのは、XOR(排他的論理和)による反転状態の効率的な管理です。各ステップで実際にリストを書き換える代わりに、「現時点でこの位置が反転済みかどうか」を flipped 変数で追跡します。さらに、反転操作の影響が終了する位置(i + k)を to_conv リストに記録しておき、その位置に到達した時点で反転状態を解除します。これにより、各要素を一度だけ処理すればよくなり、全体を線形時間で解くことが可能になります。

実装例

理解を深めるために、以下のPythonコードを見てみましょう。

class Solution:
   def solve(self, nums, k):
      n = len(nums)
      res = 0
      flipped = 0
      to_conv = [0] * n
      for i in range(n):
         flipped ^= to_conv[i]
         cur = nums[i]
         cur ^= flipped
         if cur == 1:
            flipped ^= 1
            res += 1
            if i + k - 1 >= n:
               return -1
            if i + k < n:
               to_conv[i + k] = 1
      return res
ob = Solution()
nums = [1,1,1,0,0,1,1,1]
k = 3
print(ob.solve(nums, k))

入力

[1,1,1,0,0,1,1,1], 3

出力

2

計算量の分析

時間計算量: O(n) — リストを一度だけ走査するため、要素数に対して線形時間で処理できます。
空間計算量: O(n) — 反転終了位置を記録するための補助リスト to_conv が必要です。

素朴なアプローチでは各反転ごとにk個の要素を書き換える必要があり、最悪の場合 O(n×k) の時間がかかりますが、このXORを使った手法なら大規模な入力でも高速に動作します。

  1. Pythonでリストの全順列における特別な値Sの平均を計算するプログラム

    問題の概要要素のリストが与えられたとき、次のアルゴリズムに従って値Sを計算できるものとします。while L のサイズが 1 より大きい間、繰り返す:    a := L[0]    b := L[1]    L[1] を削除    L[0] := a + b + a*breturn L[0] mod (10^9 + 7)この問題では、リストLのすべての可能な順列(並べ替え)から計算されるSの値の平均を求める必要があります。例えば、入力

  2. Pythonで全コースを履修するのに必要な最小学期数を求めるプログラム

    問題の概要n 個のコースがあり、それぞれ 1 から n までの番号が付けられているとします。また、relations という配列が与えられ、relations[i] はペア (prevCourse_i, nextCourse_i) を含んでいます。これは「コース prevCourse_i を先に履修しなければ、コース nextCourse_i を履修できない」という前提関係を表します。さらに、最後のパラメータとして k が与えられます。1 学期あたり最大 k コースまで履修できますが、そのためには履修したいコースの前提科目を、前の学期までにすべて修了しておく必要があります。このとき、すべてのコ