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

如何从1-10000数组中找出乘积为指定值的长度30子数组?解决内存溢出

问题分析与解决方案

你的核心问题是暴力枚举组合的方式完全不可行——itertools.combinations(1到10000, 30)对应的组合数是天文数字(C(10000,30)≈10^87),内存和计算资源根本无法支撑,直接枚举必然爆内存。同时你的代码存在语法错误(未定义变量y)、逻辑错误(迭代器不能用len()),且直接计算大数乘积会溢出。

正确思路:质因数分解+动态规划

要解决这个问题,必须把乘积相等的问题转化为质因数指数求和相等的问题,完全避免直接计算大数乘积,同时用动态规划统计符合条件的组合数。

步骤拆解

  1. 目标值的质因数分解
    对于目标值(你这里是N!),用Legendre公式快速计算其质因数指数:对于质数p,N!中p的指数是sum_{i=1}^∞ floor(N/p^i),直到p^i > N。

  2. 单个数字的质因数分解
    对1到N的每个数字,分解其质因数,得到每个质数对应的指数(1没有质因数,指数全为0)。

  3. 动态规划统计组合数
    用动态规划数组dp[cnt]存储选cnt个数时,各质因数指数组合对应的组合数:

    • 初始状态:dp[0][全0指数组合] = 1(选0个数的情况只有1种)
    • 遍历每个数字的指数组合,倒序更新dp:对于每个已有的dp[cnt][当前指数],加上当前数字的指数得到新的指数组合,累加组合数
    • 最终dp[30][目标指数组合]就是答案

修正后的实现代码

import math
from collections import defaultdict

def legendre(n, p):
    # 计算n!中质数p的指数
    count = 0
    while n > 0:
        n = n // p
        count += n
    return count

def factorize(num):
    # 分解单个数字的质因数,返回{质数:指数}
    factors = {}
    if num == 1:
        return factors
    # 处理2的情况
    while num % 2 == 0:
        factors[2] = factors.get(2, 0) + 1
        num = num // 2
    # 处理奇数
    i = 3
    while i*i <= num:
        while num % i == 0:
            factors[i] = factors.get(i, 0) + 1
            num = num // i
        i += 2
    if num > 1:
        factors[num] = 1
    return factors

def count_valid_combinations(N, k):
    # 生成N以内的所有质数(埃氏筛)
    sieve = [True] * (N + 1)
    sieve[0] = sieve[1] = False
    for i in range(2, int(math.sqrt(N)) + 1):
        if sieve[i]:
            sieve[i*i : N+1 : i] = [False] * len(sieve[i*i : N+1 : i])
    primes = [i for i, is_prime in enumerate(sieve) if is_prime]
    
    # 计算目标值N!的质因数指数元组
    target_exps = [legendre(N, p) for p in primes]
    target_tuple = tuple(target_exps)
    
    # 把1~N的每个数转换成对应质数索引的指数元组
    num_exp_tuples = []
    for num in range(1, N + 1):
        factor_dict = factorize(num)
        exp_list = [factor_dict.get(p, 0) for p in primes]
        num_exp_tuples.append(tuple(exp_list))
    
    # 动态规划初始化:dp[cnt]存储选cnt个数时的指数组合->组合数
    dp = [defaultdict(int) for _ in range(k + 1)]
    dp[0][tuple([0]*len(primes))] = 1
    
    # 遍历每个数的指数组合,倒序更新dp避免重复选同一个数
    for exp_tuple in num_exp_tuples:
        for cnt in range(k-1, -1, -1):
            for curr_exp, curr_count in list(dp[cnt].items()):
                # 计算新的指数组合
                new_exp = tuple(c + e for c, e in zip(curr_exp, exp_tuple))
                # 剪枝:如果新指数超过目标,直接跳过
                if any(ne > te for ne, te in zip(new_exp, target_tuple)):
                    continue
                dp[cnt+1][new_exp] += curr_count
    
    return dp[k].get(target_tuple, 0)

# 测试示例:N=10,k=3,统计乘积等于10!的长度3子数组数量
# print(count_valid_combinations(10, 3))

额外优化建议

  1. 提前过滤无效数字:如果某个数字的某质因数指数已经超过目标值的对应指数,直接排除该数字,减少计算量。
  2. 单独处理数字1:1的质因数指数全为0,可统计1的数量m,拆分问题为选t个1(t从0到min(k,m)),剩下k-t个非1数字的指数和等于目标,分别计算后累加结果,能大幅减少动态规划的状态数。
  3. 使用更高效的状态存储:可以用数组代替字典存储指数组合(如果质数数量可控),进一步提升效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 08:09:24