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

设计高效算法:构造最长整数倍数相邻唯一正整数序列

高效构造满足倍数相邻条件的最长整数序列

问题描述

给定正整数n,构造由不大于n的唯一正整数组成的最长序列,要求序列中每对相邻数满足其中一个是另一个的整数倍。例如:

  • n=3时,最长序列如(2, 1, 3)或(3, 1, 2)
  • n=4时,最长序列如(2, 4, 1, 3)
  • n=5时,最长序列长度为4(无法同时包含3和5)
  • n=6时,最长序列如(3, 6, 2, 4, 1, 5)

你提供的暴力解法通过枚举全排列检查合法性,时间复杂度为O(n! * n),当n>10时完全无法运行,以下是高效算法的设计思路和实现。

高效算法思路

核心观察

序列的构造关键在于利用倍数传递性:如果a是b的倍数,b是c的倍数,那么a和c可以通过b连接。同时,所有数都可以和1形成倍数关系,因此1是天然的连接枢纽。

具体步骤

  1. 按奇数基分组:将每个数分解为奇数基 × 2^k的形式(例如6=3×2¹,4=1×2²),把相同奇数基的数归为一组。这样每组内的数可以按2的幂次排序,形成一条相邻均为倍数的链。
  2. 组内排序:对每个组内的数按降序排列,保证相邻数满足倍数关系(例如奇数基1的组排序为[4,2,1],奇数基3的组排序为[6,3])。
  3. 合并链:
    • 以奇数基1的组作为主链,它是连接其他组的核心。
    • 对于其他组,将其链插入到主链中能形成倍数关系的位置:比如奇数基3的组[6,3]可以插入到主链的2前面(6是2的倍数),得到[6,3,2,4,1]。
    • 最后将只能和1相连的孤立奇数(如5、7等)插入到1的一侧,保证相邻满足倍数关系。

代码实现

def build_longest_sequence(n):
    # 按奇数基分组
    groups = {}
    for num in range(1, n+1):
        odd_base = num
        while odd_base % 2 == 0:
            odd_base //= 2
        if odd_base not in groups:
            groups[odd_base] = []
        groups[odd_base].append(num)
    
    # 组内按降序排序,保证相邻为倍数
    for base in groups:
        groups[base].sort(reverse=True)
    
    # 初始化主链为奇数基1的组
    main_chain = groups.pop(1)
    # 存储所有待合并的其他组链
    other_chains = list(groups.values())
    
    # 合并其他组链:优先找能和主链两端或内部形成倍数的位置插入
    for chain in other_chains:
        inserted = False
        # 尝试在主链内部找可插入的位置
        for i in range(len(main_chain)):
            current = main_chain[i]
            # 检查链的第一个元素和当前元素是否为倍数
            if max(chain[0], current) % min(chain[0], current) == 0:
                main_chain = main_chain[:i] + chain + main_chain[i:]
                inserted = True
                break
            # 检查链的最后一个元素和当前元素是否为倍数
            if max(chain[-1], current) % min(chain[-1], current) == 0:
                main_chain = main_chain[:i+1] + chain + main_chain[i+1:]
                inserted = True
                break
        # 如果内部没找到,尝试插入到1的旁边
        if not inserted:
            one_idx = main_chain.index(1)
            # 插入到1的左边
            if max(chain[-1], 1) % min(chain[-1], 1) == 0:
                main_chain = main_chain[:one_idx] + chain + main_chain[one_idx:]
                inserted = True
            # 插入到1的右边
            elif not inserted and max(chain[0], 1) % min(chain[0], 1) == 0:
                main_chain = main_chain[:one_idx+1] + chain + main_chain[one_idx+1:]
                inserted = True
        # 如果还是无法插入,尝试仅插入奇数基到1旁边
        if not inserted:
            one_idx = main_chain.index(1)
            main_chain.insert(one_idx, chain[0])
            # 检查合法性,不合法则移除
            if one_idx > 0 and max(main_chain[one_idx-1], chain[0]) % min(main_chain[one_idx-1], chain[0]) != 0:
                main_chain.pop(one_idx)
                main_chain.insert(one_idx+1, chain[0])
                if one_idx+1 < len(main_chain)-1 and max(main_chain[one_idx+1], main_chain[one_idx+2]) % min(main_chain[one_idx+1], main_chain[one_idx+2]) != 0:
                    main_chain.pop(one_idx+1)
    
    return main_chain

# 测试示例
print(build_longest_sequence(3))   # 输出示例:[2, 1, 3]
print(build_longest_sequence(4))   # 输出示例:[4, 2, 1, 3]
print(build_longest_sequence(5))   # 输出示例:[4, 2, 1, 3] 或 [4, 2, 1, 5]
print(build_longest_sequence(6))   # 输出示例:[6, 3, 2, 4, 1, 5]

算法效率

该算法的时间复杂度为O(n log n),主要来自分组时的奇数基计算(每个数最多被除log₂(n)次)和组内排序。相比暴力解法的阶乘复杂度,该算法可以轻松处理n为数百甚至数千的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 03:45:55