📌  相关文章
📜  将数组拆分为 K 个不重叠的子集,使得所有子集和中的最大值最小(1)

📅  最后修改于: 2023-12-03 15:25:19.610000             🧑  作者: Mango

将数组拆分为 K 个不重叠的子集,使得所有子集和中的最大值最小

问题描述

给定一个整数数组 nums 和一个正整数 K,将数组拆分为 K 个不重叠的子集,使得所有子集和中的最大值最小。

解决方案

此问题属于搜索和二分的结合。首先我们需要确定最大值的范围,在本题中最小可能的最大值为 max(nums),最大可能的最大值为 sum(nums),我们可以用二分法查找最小的满足条件的最大值。对于最小的最大值 mid,我们可以用 DFS 进行搜索,每次搜索时尝试将一个元素加入到当前的子集中,如果当前子集的和不超过 mid,则将其加入到当前子集中,否则进行回溯操作,换一条路径进行搜索。

如果当前的搜索路径能够构建出 K 个不重叠的子集,则说明 mid 值的范围可以往左缩小,否则 mid 值的范围需要往右扩大。

备注

时间复杂度为 O(2^n),其中 n 为数组的长度。限制时间复杂度,可以加入相应的剪枝。

代码实现
from typing import List

class Solution:
    def canSplit(self, nums: List[int], k: int, mid: int, used: List[bool], cur: int) -> bool:
        if k == 1:
            return True
        if cur == mid:
            return self.canSplit(nums, k-1, mid, used, 0)
        for i in range(len(nums)):
            if not used[i] and cur + nums[i] <= mid:
                used[i] = True
                if self.canSplit(nums, k, mid, used, cur+nums[i]):
                    return True
                used[i] = False
        return False

    def splitArray(self, nums: List[int], k: int) -> int:
        left, right = max(nums), sum(nums)
        while left <= right:
            mid = left + (right - left) // 2
            if self.canSplit(nums, k, mid, [False]*len(nums), 0):
                right = mid - 1
            else:
                left = mid + 1
        return left
参考资料
  • Leetcode 题目地址: https://leetcode.com/problems/split-array-largest-sum/
  • Leetcode 题解: https://leetcode.com/problems/split-array-largest-sum/solution/
  • 博客园: https://www.cnblogs.com/grandyang/p/6083390.html