You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求高效算法:14位重复数字组合的差值匹配问题优化

优化含重复数字的14位整数组合查找算法

问题背景

需要从包含重复数字的14位数字列表[2,2,2,2,4,4,5,5,5,6,6,6,8,8]中,找到满足小于该整数的组合数比大于它的组合数多5617961的目标整数。原代码使用itertools.permutations生成所有排列再遍历对比,因总唯一排列数超过2500万,运行效率极低,完全无法实用。

原代码核心问题

  1. 全排列生成开销巨大:带重复元素的14位数字唯一排列数为14!/(4!×2!×3!×3!×2!)=25225200,生成并遍历所有排列的计算量远超普通计算机处理能力。
  2. 双重遍历全排列:先筛选开头为58的数,再对每个筛选出的数重新遍历全排列计算差值,时间复杂度呈指数级增长。

优化思路:用组合数学计算,避免生成全排列

核心是通过数学推导确定目标数在升序排列中的位置,再按位构造出该数,无需生成任何排列:

  1. 推导目标位置:
    设总唯一排列数为N,小于目标数的组合数为less,大于的为greater,根据条件联立方程:
    less - greater = 5617961
    less + greater = N - 1  # 排除目标数自身
    
    计算得:less = (5617961 + N - 1) // 2,目标数是升序排列中的第less + 1个(前面有less个比它小的数)。
  2. 按位构造目标数:
    从最高位开始,依次尝试每个可能的数字,计算剩余数字的排列数,判断目标位置是否落在当前数字对应的排列区间内,逐步确定每一位的数字。

优化后代码实现

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("不存在满足条件的整数")

代码说明

  1. count_permutations:通过阶乘除法计算当前数字集合的唯一排列数,避免生成所有排列,计算效率极高。
  2. find_kth_permutation:按位构造目标数,每次从小到大尝试数字,通过剩余排列数判断目标位置,时间复杂度仅为O(位数×不同数字数量),运行瞬间出结果。
  3. 推导逻辑:通过数学公式直接定位目标数的位置,无需遍历任何排列,彻底解决原代码的效率问题。

内容的提问来源于stack exchange,提问作者tomaito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 16:05:32