等积子集的划分方案-LeetCode
3566. 等积子集的划分方案 - Partition Array into Two Equal Product Subsets
🎯 问题描述(来源于LeetCode)
描述:
给定一个只包含不同正整数的数组 nums 和一个整数 target。你必须把 nums 所有元素分成两个非空且不相交的子集,每个元素恰好属于其中一个子集,使得两个子集的元素乘积都等于 target。若能找到则返回 true,否则返回 false。
说明:
- 每个元素只能属于其中一组,且两组都不能为空。
- 所有
nums中的元素互不相同。 - 元素乘积可能非常大,需注意溢出(可使用 Python 大整数,或使用
target的质因数分解优化,但本题数据范围小,暴力回溯即可)。
示例:
- 示例 1:
1 | 输入: nums = [3,1,6,8,4], target = 24 |
- 示例 2:
1 | 输入: nums = [2,5,3,7], target = 15 |
💻 解题思路
思路:回溯法(DFS) + 剪枝 + 非空子集验证
算法步骤
-
前置判断(总乘积)
计算nums所有元素的乘积total_product,如果total_product != target * target,直接返回False(必要不充分条件,但可快速排除)。 -
回溯搜索
定义dfs(i, cur_product, cnt),表示当前考虑到下标i,已选子集的乘积为cur_product,已选元素个数为cnt:- 如果
i == n:所有元素处理完毕,此时若cur_product == target且0 < cnt < n(即两个子集均非空),则返回True,否则返回False。 - 不选
nums[i]:递归dfs(i+1, cur_product, cnt),若返回True则直接返回。 - 选
nums[i]:将cur_product乘以nums[i],若新乘积不超过target(剪枝),则递归dfs(i+1, cur_product * nums[i], cnt+1),若返回True则直接返回。 - 如果以上分支均未成功,返回
False。
- 如果
-
从
dfs(0, 1, 0)开始调用(初始乘积为 1,已选 0 个元素)。 -
返回最终结果。
代码实现
1 | from typing import List |
📊 性能分析
- 时间复杂度:最坏 ,但通过排序 + 乘积剪枝,实际运行远快于朴素回溯。
- 空间复杂度:,递归栈深度。
思考
- 通过
cnt参数确保子集非空。 - 为了进一步提高剪枝效率,将
nums降序排列,使较大元素优先尝试,能更快超过target从而回溯,减少搜索空间。 - 若数组长度较大(例如 > 20),回溯仍可能超时,此时可考虑 Meet-in-the-Middle 或 DP(但由于乘积巨大,DP 不现实)。题目数据范围通常较小,此解法足够。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






