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

十六进制Armstrong数查找算法优化问询:10位计算提速需求

针对你的十六进制Armstrong数计算优化需求,我整理了几个实用的方向,每个都能帮你大幅压缩运行时间,尤其是10位这种较大的位数场景:

1. 预计算幂值+批量求和,替代逐个累加

你当前的genPow可以简化为一个字典,提前缓存0-f每个字符的digits次方值,而且求和时不用逐个遍历组合里的字符,而是按字符出现的次数批量计算——比如组合里有3个5,直接用3 * pow_dict['5'],省去循环开销:

# 预计算幂字典,替代genPow
pow_dict = {d: int(d, 16)**digits for d in '0123456789abcdef'}
# 计算组合的幂和时,用计数批量计算
from collections import Counter
comb_counter = Counter(comb)
sum_val = sum(count * pow_dict[d] for d, count in comb_counter.items())

2. 提前剪枝无效组合,避免无用计算

在生成组合或计算幂和的过程中,直接跳过不可能符合条件的情况:

  • 范围剪枝:先算出digits位十六进制数的范围:lower = 16 ** (digits-1),upper = (16 ** digits) - 1。如果计算出的sum_val不在这个区间里,直接跳过,不用再转成十六进制字符串。
  • 累加中途剪枝:如果在批量求和前,发现当前已选字符的幂和加上剩余位置全填最大字符f的幂和仍小于lower,或者加上剩余位置全填最小字符0的幂和仍大于upper,直接跳过这个分支(递归实现时这一点更高效)。

3. 优化组合与幂和的匹配逻辑,抛弃Counter的低效操作

当前的check函数用Counter的减法比较,其实可以把字符计数转换成固定顺序的元组,直接做等值判断,速度快很多:

# 把字符序列的计数转换成元组(按0-f的顺序统计次数)
def get_count_tuple(s):
    count = [0]*16
    for c in s:
        count[int(c,16)] += 1
    return tuple(count)

# 组合的计数元组
comb_tuple = get_count_tuple(comb)
# 幂和转十六进制后的计数元组
hex_str = format(sum_val, 'x')
hex_tuple = get_count_tuple(hex_str)
# 直接比较元组,比Counter操作快数倍
if comb_tuple == hex_tuple:
    results.append(hex_str)

这种方式是针对固定的16个字符做定向统计,没有通用Counter的额外开销,匹配效率会大幅提升。

4. 用递归生成组合+剪枝,替代itertools的全量生成

递归方案的核心优势是边生成边剪枝,而不是先生成所有组合再过滤。比如递归函数可以跟踪当前选到的字符索引、已选位数、当前幂和、计数元组,每一步都判断是否还有可能符合条件,不符合就直接终止分支:

def recursive_armstrong(digits):
    pow_vals = [i**digits for i in range(16)]  # 预计算0-f的digits次方
    lower = 16 ** (digits-1)
    upper = (16**digits) - 1
    results = set()

    def backtrack(start, remaining, current_sum, count):
        if remaining == 0:
            if lower <= current_sum <= upper:
                hex_str = format(current_sum, 'x')
                # 生成hex_str的计数元组
                hex_count = [0]*16
                for c in hex_str:
                    hex_count[int(c,16)] += 1
                if tuple(hex_count) == tuple(count):
                    results.add(hex_str)
            return
        # 从start开始选,避免生成重复组合(比如选1后不再选0)
        for i in range(start, 16):
            # 剪枝:即使剩下全选当前字符,总和仍不够下限,跳过
            max_possible = current_sum + remaining * pow_vals[i]
            if max_possible < lower:
                continue
            # 尝试选k个当前字符,k从1到剩余位数
            for k in range(1, remaining+1):
                new_sum = current_sum + k * pow_vals[i]
                if new_sum > upper:
                    break  # 再选更多会超上限,直接跳出循环
                count[i] += k
                backtrack(i, remaining - k, new_sum, count)
                count[i] -= k

    backtrack(0, digits, 0, [0]*16)
    return sorted(results)

这个递归版本会在每一步跳过那些不可能满足范围的分支,大幅减少无效计算量,对于10位这种场景,效率提升会非常明显。

5. 用位运算判断十六进制位数,避免字符串转换开销

在判断sum_val的十六进制位数是否等于digits时,不用先转成字符串再取长度,可以用位运算快速计算:

# 十六进制位数 = ceil(二进制位数 /4) = (二进制位数 +3) //4
if (sum_val.bit_length() +3) //4 != digits:
    continue

这比len(format(sum_val, 'x'))快很多,因为字符串转换是相对耗时的操作,能省则省。

把这些优化结合起来,10位十六进制Armstrong数的计算时间应该能从60秒压缩到几秒以内。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:38:55