求高效算法:14位重复数字组合的差值匹配问题优化
优化含重复数字的14位整数组合查找算法
问题背景
需要从包含重复数字的14位数字列表[2,2,2,2,4,4,5,5,5,6,6,6,8,8]中,找到满足小于该整数的组合数比大于它的组合数多5617961的目标整数。原代码使用itertools.permutations生成所有排列再遍历对比,因总唯一排列数超过2500万,运行效率极低,完全无法实用。
原代码核心问题
- 全排列生成开销巨大:带重复元素的14位数字唯一排列数为
14!/(4!×2!×3!×3!×2!)=25225200,生成并遍历所有排列的计算量远超普通计算机处理能力。 - 双重遍历全排列:先筛选开头为
58的数,再对每个筛选出的数重新遍历全排列计算差值,时间复杂度呈指数级增长。
优化思路:用组合数学计算,避免生成全排列
核心是通过数学推导确定目标数在升序排列中的位置,再按位构造出该数,无需生成任何排列:
- 推导目标位置:
设总唯一排列数为N,小于目标数的组合数为less,大于的为greater,根据条件联立方程:
计算得:less - greater = 5617961 less + greater = N - 1 # 排除目标数自身less = (5617961 + N - 1) // 2,目标数是升序排列中的第less + 1个(前面有less个比它小的数)。 - 按位构造目标数:
从最高位开始,依次尝试每个可能的数字,计算剩余数字的排列数,判断目标位置是否落在当前数字对应的排列区间内,逐步确定每一位的数字。
优化后代码实现
import math from collections import Counter def count_permutations(counts): # 计算当前数字计数下的唯一排列数 total = sum(counts.values()) if total == 0: return 1 fact_total = math.factorial(total) denominator = 1 for cnt in counts.values(): denominator *= math.factorial(cnt) return fact_total // denominator def find_kth_permutation(original_counts, k): # 找到升序排列中的第k个唯一排列(k从1开始计数) counts = Counter(original_counts) result = [] remaining = sum(counts.values()) for _ in range(remaining): # 按升序遍历每个可选数字 for num in sorted(counts.keys()): if counts[num] == 0: continue # 尝试将当前数字作为当前位,计算剩余排列数 counts[num] -= 1 perm_count = count_permutations(counts) if perm_count >= k: result.append(str(num)) break else: # 目标不在当前数字的区间,减去该区间的排列数,尝试下一个数字 k -= perm_count counts[num] += 1 else: raise ValueError("目标位置超出总排列数范围") return ''.join(result) # 初始数字列表 lst = [2, 2, 2, 2, 4, 4, 5, 5, 5, 6, 6, 6, 8, 8] original_counts = Counter(lst) # 计算总唯一排列数 total_perms = count_permutations(original_counts) print(f"总唯一排列数: {total_perms}") # 根据条件计算目标排列的位置k less = (5617961 + total_perms - 1) // 2 target_k = less + 1 # 验证位置合法性并查找目标数 if 1 <= target_k <= total_perms: target_num = find_kth_permutation(original_counts, target_k) print(f"满足条件的目标整数: {target_num}") # 可选:验证是否符合开头为58的要求 if target_num.startswith('58'): print("该整数符合开头为58的筛选条件") else: print("该整数不符合开头为58的筛选条件") else: print("不存在满足条件的整数")
代码说明
count_permutations:通过阶乘除法计算当前数字集合的唯一排列数,避免生成所有排列,计算效率极高。find_kth_permutation:按位构造目标数,每次从小到大尝试数字,通过剩余排列数判断目标位置,时间复杂度仅为O(位数×不同数字数量),运行瞬间出结果。- 推导逻辑:通过数学公式直接定位目标数的位置,无需遍历任何排列,彻底解决原代码的效率问题。
内容的提问来源于stack exchange,提问作者tomaito
相关产品推荐
相关产品推荐

