子集和求解性能优化:folder2运算耗时过长的解决方案
优化子集和匹配效率的解决方案
你的核心问题是暴力枚举所有子集的时间复杂度为O(2^n),当folder2有35个元素时,子集总数超过340亿,完全无法在合理时间内完成计算。以下是针对性的优化方案,通过动态规划将时间复杂度降至多项式级别:
核心优化思路
- 替换暴力枚举为动态规划(DP),仅保留可能接近目标值的子集和,避免遍历所有组合
- 预处理单个元素的最优解,用于后续剪枝
- 对元素排序,优先处理大元素,快速锁定较优解并减少无效计算
- 剪枝掉不可能产生更优结果的元素与组合
优化后的代码实现
def find_closest_subset(target, items): # 按元素值从大到小排序,优先处理大元素,更快锁定优解 sorted_items = sorted(items, key=lambda x: -x[1]) # 初始化最优结果:最小差值、对应和、子集元素 min_diff = float('inf') best_sum = 0.0 best_subset = [] # 先处理单个元素的情况,获取初始最优解 for key, val in sorted_items: current_diff = abs(target - val) if current_diff < min_diff: min_diff = current_diff best_sum = val best_subset = [(key, val)] elif current_diff == min_diff: # 差值相同时,选择更接近目标的和(这里取更大的和) if val > best_sum: best_sum = val best_subset = [(key, val)] # 动态规划字典:键=子集和,值=对应的子集元素列表 dp = {} for key, val in sorted_items: # 剪枝:单个元素差值已大于当前最优,且元素值超过目标,组合后只会更差,直接跳过 if abs(target - val) > min_diff and val > target: continue # 遍历当前DP的副本,避免修改原字典导致循环异常 temp_dp = dp.copy() for existing_sum, existing_subset in temp_dp.items(): new_sum = existing_sum + val new_diff = abs(target - new_sum) # 更新最优结果 if new_diff < min_diff: min_diff = new_diff best_sum = new_sum best_subset = existing_subset + [(key, val)] elif new_diff == min_diff: if new_sum > best_sum: best_sum = new_sum best_subset = existing_subset + [(key, val)] # 仅保留差值不超过当前最优的和,压缩DP空间 if new_diff <= min_diff + 1e-9: # 处理浮点数精度问题 dp[new_sum] = existing_subset + [(key, val)] # 将当前元素单独加入DP(如果未存在) if val not in dp: dp[val] = [(key, val)] return dict(best_subset) # 测试代码 folder2 = {'10__PYTHON_ENV': 80.29044818878174, '1__YAPAY_ZEKA': 34.33022499084473, '2__ALTYAPI_BORU_HESABI': 0.06213569641113281, '3__BEST_ALGORIYTMS': 10.487943649291992, '4__DENGELEME_HESABI': 0.2784423828125, '5__COIN_ALERT': 9.173674583435059, '6__PYTHON_KURP_HESAPLARI': 6.0962066650390625, '7__SQL_TUTORIAL': 26.39926815032959, '8__2023_02_15_desktop': 165.68173027038574, '9__ICONS': 1.1095151901245117, 'ANACONDA_SETUPS': 2206.1647415161133, 'BEETIND_ODDS': 52.650081634521484, 'BINANCE_KALDIRACLI_ISLM': 0.00225067138671875, 'BLOCKCHAIN': 101.93277072906494, 'CLASS_YAPILARI': 0.014241218566894531, 'DOSYA_BOYUTU_VE_KOPYALA': 0.0019941329956054688, 'EXCEL_VERI_YAZMA_OKUMA': 0.3079366683959961, 'GENETIC_ALGARITYM': 0.01592254638671875, 'GOOGLE_EARTH_DURATION_TIME_PATH': 0.008657455444335938, 'MATPLOTLIB': 0.0037221908569335938, 'MATPLOTLIB_read_txt': 0.0011882781982421875, 'MURAT_OZUN_VIDEO': 403.7390956878662, 'OGRENCI_TAKIP': 175.95281600952148, 'PANDAS_READ_EXCEL': 0.008481979370117188, 'PDF_CREATE': 0.001903533935546875, 'PLOTLY': 0.0038166046142578125, 'pyautocad': 0.844517707824707, 'Py_to_Exe': 251.8494005203247, 'sqlite_db_exam': 0.008614540100097656, 'TAYFUN_SEF': 0.033402442932128906, 'TIRENDAS_AKADEMI': 153.01508235931396, 'TKINTER': 0.00034427642822265625, 'TUGRUL_AILE': 659.8760471343994, 'TURTLE': 0.0038967132568359375, 'TXT_OKU': 0.00572967529296875, 'TXT_OKU_DENEME': 0.0009374618530273438} result = find_closest_subset(100, folder2.items()) for key, val in result.items(): print(f"{key} --> {val}") print(f"\n子集总和: {sum(result.values())}") print(f"与目标值100的差值: {abs(100 - sum(result.values()))}")
关键优化点说明
- 动态规划核心:通过维护一个字典记录所有可能的子集和及其对应的元素,避免遍历所有组合,时间复杂度降至O(n*K)(n为元素数量,K为有效子集和的数量,此处K远小于目标值100)
- 剪枝策略:跳过单个元素差值已大于当前最优的元素,尤其是那些远大于目标值的元素(如ANACONDA_SETUPS),避免无效计算
- 排序优化:优先处理大元素,能快速找到接近目标的子集,提前更新最优解,进一步减少后续计算量
- 浮点数处理:加入1e-9的精度容错,避免浮点数精度误差导致的判断错误
内容的提问来源于stack exchange,提问作者Tugrul
相关产品推荐
相关产品推荐

