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

Pythonで解くダイエットプランのパフォーマンス問題 ― スライディングウィンドウによる効率的な実装

ダイエット中の人が i 日目に摂取したカロリーを calories[i] と表します。整数 k が与えられたとき、連続する k 日間の各区間(calories[i], calories[i+1], ..., calories[i+k-1]、ただし 0 <= i <= n-k)について、その期間の合計カロリー T を計算し、次のルールに従ってポイントを評価します。

  • T が下限(lower)より小さい場合:ダイエットの成果が不良のため、1ポイント減点
  • T が上限(upper)より大きい場合:ダイエットの成果が良好なため、1ポイント加点
  • それ以外の場合:正常な範囲内のため、ポイント変動なし

ダイエット開始時のポイントは0です。このとき、最終的な合計ポイントを求めるのが本問題の目的です。

具体例

配列が [6,5,0,0]k = 2lower = 1upper = 5 の場合を考えてみましょう。

  • C[0] + C[1] = 11 > upper なので、1ポイント加算
  • lower <= C[1] + C[2] = 5 <= upper なので、変化なし
  • C[2] + C[3] = 0 < lower なので、1ポイント減点

加算と減点が相殺されるため、出力は 0 となります。

解法のアプローチ:スライディングウィンドウ

すべての区間に対して毎回合計を再計算すると非効率ですが、スライディングウィンドウ(尺取り法)を使えば、直前の区間の合計を再利用できるため、全体を線形時間 O(n) で処理できます。手順は以下の通りです。

  • temp = 0 で初期化する
  • i を 0 から k-1 までループし、temp += C[i] で最初のウィンドウの合計を求める
  • right = k - 1left = 0points = 0 で初期化する
  • rightC の長さ未満である間、以下を繰り返す:
    • temp < lower なら points を1減らし、temp > upper なら1増やす
    • temp -= C[left] で左端の要素をウィンドウから除外する
    • leftright をそれぞれ1進める
    • right が配列の長さ以上になったらループを抜ける
    • temp += C[right] で新しい右端の要素をウィンドウに追加する
  • 最後に points を返す

実装例

以下はPythonでの実装例です。

class Solution(object):
    def dietPlanPerformance(self, c, k, l, u):
        temp = 0
        for i in range(k):
            temp += c[i]
        right = k - 1
        left = 0
        points = 0
        while right < len(c):
            if temp < l:
                points -= 1
            elif temp > u:
                points += 1
            temp -= c[left]
            left += 1
            right += 1
            if right >= len(c):
                break
            temp += c[right]
        return points

ob1 = Solution()
print(ob1.dietPlanPerformance([6,5,0,0], 2, 1, 5))

入力

[6,5,0,0]
2
1
5

出力

0

まとめ

この問題は、固定長の区間和を繰り返し評価する典型的なスライディングウィンドウの応用例です。各ステップでウィンドウから外れる要素を引き、新しく入る要素を足すだけでよいため、計算量は O(n)、空間計算量は O(1) に抑えられます。累積和(プレフィックスサム)を使う方法でも解けますが、ウィンドウ幅 k が既知の場合はこの手法が最もシンプルで効率的です。

  1. Pythonでパスカルの三角形のn番目の行を求める方法を解説

    パスカルの三角形とはある数 n が与えられたとき、パスカルの三角形の n 番目(0始まり)の行を求めることを考えます。パスカルの三角形は、次のようなルールで作成できます。最上行は「1」のみで構成される2行目以降は、左上の数と右上の数を足し合わせた値が並ぶ具体的には、以下のような形になります。例えば入力が 4 の場合、出力は [1, 4, 6, 4, 1] となります。解法のアプローチこの問題は、以下の手順で解くことができます。n が 0 の場合 → [1] を返すn が 1 の場合 → [1, 1] を返すls を [1, 1]、temp を [1, 1] として初期化するi を 2 から n

  2. Pythonで二分木の最大深度を求める方法|再帰を使った実装例を解説

    Pythonで二分木の最大深度を求める二分木が与えられたとき、その最大深度を求める問題を考えます。木の最大深度とは、根(ルート)から葉ノードまでの最も長い経路をたどったときに通過するノード数のことです。例えば、下図のような二分木の場合、最大深度は 3 となります。解法のアプローチこの問題は再帰を使うことで、非常にシンプルに解くことができます。手順は以下のとおりです。再帰用のヘルパーメソッド solve(root, depth=0) を定義します。root が空(None)の場合は、そこまでの深さ depth をそのまま返します。それ以外の場合は、左部分木に対する solve(left, dep