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 = 2、lower = 1、upper = 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 - 1、left = 0、points = 0で初期化するrightがCの長さ未満である間、以下を繰り返す:temp < lowerならpointsを1減らし、temp > upperなら1増やすtemp -= C[left]で左端の要素をウィンドウから除外するleftとrightをそれぞれ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 が既知の場合はこの手法が最もシンプルで効率的です。
-
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
-
Pythonで二分木の最大深度を求める方法|再帰を使った実装例を解説
Pythonで二分木の最大深度を求める二分木が与えられたとき、その最大深度を求める問題を考えます。木の最大深度とは、根(ルート)から葉ノードまでの最も長い経路をたどったときに通過するノード数のことです。例えば、下図のような二分木の場合、最大深度は 3 となります。解法のアプローチこの問題は再帰を使うことで、非常にシンプルに解くことができます。手順は以下のとおりです。再帰用のヘルパーメソッド solve(root, depth=0) を定義します。root が空(None)の場合は、そこまでの深さ depth をそのまま返します。それ以外の場合は、左部分木に対する solve(left, dep