LC 698. 划分为 k 个相等的子集 (opens new window) (opens new window)
中等
# 问题描述
给定一个整数数组 nums
和一个正整数 k
,找出是否有可能把这个数组分成 k
个非空子集,其总和都相等。
示例 1:
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
输出: True
说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
示例 2:
输入: nums = [1,2,3,4], k = 3
输出: false
提示:
1 <= k <= len(nums) <= 16
0 < nums[i] < 10000
- 每个元素的频率在
[1,4]
范围内
# 回溯 + 剪枝
首先对数组进行一下预处理,计算是否有可能分成 个和相等的非空子集,若不能则返回 。其次是计算出平均值 后,查看数组中是否存在比平均值大的值,若存在,则返回 。然后创建出 个容量大小为 的桶,遍历数组,尝试将数字放入满足要求的桶中,若失败,则进行回溯,直到最后若所有数字都能够放入桶中则返回 , 否则返回 。过程需要剪枝以减少时间消耗。
/**
* @param {number[]} nums
* @param {number} k
* @return {boolean}
*/
var canPartitionKSubsets = function (nums, k) {
const sum = nums.reduce((s, v) => s + v, 0)
if (sum % k !== 0) return false
const avg = sum / k
// 剪枝一 排序
nums.sort((a, b) => b - a)
if (nums[0] > avg) return false
const n = nums.length
const buckets = new Array(n).fill(avg)
const dfs = (idx) => {
if (idx >= n) return true
for (let i = 0; i < k; i++) {
if (nums[idx] > buckets[i]) continue
// 剪枝二 与上一个桶情况一样可以直接跳过
if (i > 0 && buckets[i] === buckets[i - 1]) continue
buckets[i] -= nums[idx]
if (dfs(idx + 1)) return true
buckets[i] += nums[idx]
}
return false
}
return dfs(0)
}
- 时间复杂度:,其中 为数组 的长度,共有 个状态,每一个状态进行了 次尝试。
- 空间复杂度:
上次更新: 2023/01/31 19:48:05
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 , 转载请注明出处!