Pythonで最小グループの合計が最大になるようリストをk個に分割する方法
問題概要
数値のリスト nums と整数 k が与えられたとします。このリストを「連続する要素からなる」k個のグループに分割することを考えます。ここで「最小グループ」とは、各グループの合計値の中で最も小さいものを持つグループのことです。求めたいのは、その最小グループの合計値が取りうる最大値です。
例として、nums = [2, 6, 4, 5, 8]、k = 3 の場合を見てみましょう。リストを [2, 6]、[4, 5]、[8] の3つのグループに分割すると、それぞれの合計は 8、9、8 となり、最小グループの合計は 8 になります。どのように分割しても最小グループの合計が 8 を超えることはできないため、答えは 8 です。
解き方:二分探索(バイナリサーチ)
この問題は「答えを決め打ちして判定する」二分探索で効率的に解けます。ある値 target に対して「すべてのグループの合計を target 以上にできるか」を判定する関数 is_divisible() を用意し、答えの候補範囲を狭めていきます。target が達成可能なら、それより小さい値も必ず達成可能であるため、判定結果には単調性があり、二分探索が成立します。
アルゴリズムの手順
- is_divisible(target) 関数を定義します。
- target が 1 以下の場合は True を返します。
- num_chunks := 0、current_sum := 0 で初期化します。
- nums の各要素 x について以下を繰り返します。
- current_sum に x を加算します。
- current_sum が target 以上になったら、current_sum を 0 に戻し、num_chunks を 1 増やします。
- num_chunks が k に達したら True を返します。
- ループが終了したら False を返します。
メイン処理の手順
- left := 1 とします。
- right := (nums の全要素の合計) ÷ k + 1 とします。
- left < right − 1 の間、以下を繰り返します。
- mid := (left + right) ÷ 2 とします。
- is_divisible(mid) が真なら left := mid、そうでなければ right := mid とします。
- 最後に left を返します。
計算量は、判定関数が O(n)、二分探索が O(log S)(S は要素の総和)なので、全体で O(n log S) となり、全分割パターンを試す方法より大幅に高速です。
Pythonでの実装例
以下の実装を見ると、動作がより理解しやすくなります。
class Solution:
def solve(self, nums, k):
def is_divisible(target):
if target <= 1:
return True
num_chunks = 0
current_sum = 0
for x in nums:
current_sum += x
if current_sum >= target:
current_sum = 0
num_chunks += 1
if num_chunks == k:
return True
return False
left = 1
right = sum(nums) // k + 1
while left < right - 1:
mid = (left + right) // 2
if is_divisible(mid):
left = mid
else:
right = mid
return left
ob = Solution()
nums = [2, 6, 4, 5, 8]
k = 3
print(ob.solve(nums, k))
入力
[2, 6, 4, 5, 8], 3
出力
8
-
Pythonで数値ペアの集合から式の最大値を求めるアルゴリズムと実装例
問題の概要 同じ要素数 N を持つ2つの配列 nums1 と nums2 が与えられているとします。ここで、1 から N までの整数からなる集合 S を考えます。S の空でない部分集合 {i1, i2, ..., ik} を選んだとき、次の式の値を最大化するのがこの問題の目的です。 (nums1[i1] + nums1[i2] + ... + nums1[ik])2 + (nums2[i1] + nums2[i2] + ... + nums2[ik])2 具体例 たとえば、入力が nums1 = [-1, 6]、nums2 = [5, 4] の場合、出力は 106 になります。これは次の3通
-
Pythonで制約付きの建物の最大高さを求めるプログラム
問題の概要整数 n と制約リスト restrictions が与えられたとします。私たちは都市に n 棟の新しい建物を一列に建てようとしていますが、高さに関するいくつかの制限があります。建物には左から順に 1 から n までの番号が付けられており、各制約は restrictions[i] = (id_i, max_height_i) の形式で表され、「id_i 番の建物の高さは max_height_i 以下でなければならない」ことを意味します。建物の高さに関する都市の規則は以下のとおりです。各建物の高さは 0 以上でなければなりません。1 番の建物(最初の建物)の高さは必ず 0 です。隣接す