摇骰子游戏 | 豆包MarsCode AI刷题

68 阅读2分钟

image.png 最容易想到的方法,使用两个vector装点数数组,最后再进行遍历比较,显然这个方法效率不高

image.png 动态规划方法

1. 使用和的分布计数代替生成组合

对于每个元素数组 arrayNarrayM,我们通常会生成所有可能的和组合。这在大数据集下会产生大量中间结果,导致内存耗尽。为了解决这一问题,我们可以采用分布计数的方式来记录各个和出现的频次,而不生成具体的组合。

例如,如果 arrayN 中一个元素为 3,则所有和可以是 1, 2, 3。通过计数,我们可以得到每个和出现的次数,而不需要直接存储每个组合。

2. 动态更新和的分布计数

为每个数组分别维护一个计数字典 a_countsb_counts。初始情况下,它们包含和为 0 的空组合。接下来:

  • 遍历数组中的每个数 num
  • 对当前所有可能的和(在 a_counts 中的和)逐一进行更新,每次将 num 拆分成所有可能的加和情况(例如 1, 2,..., num)。
  • 逐步累加到每个现有和,更新可能的新和及其出现频次。

示例:假设 arrayN = [3, 2]

  • 初始化:a_counts = {0: 1}
  • 处理 3a_counts 更新为 {1: 1, 2: 1, 3: 1}
  • 处理 2:基于当前 a_counts 的和,生成 {1+1, 1+2,...} 的分布计数。

3. 计算满足条件的组合数

通过 a_countsb_counts 得到 arrayNarrayM 中可能和的分布后,下一步是计算满足条件的组合数:

  • 设定 total 为总的组合数,即 a_countsb_counts 中所有组合的乘积。
  • 遍历 a_countsb_counts 中的每一对和,若 a_sum > b_sum,则此组合满足条件 b < a,将该组合的频次积累到计数 cnt 中。

4. 计算概率并返回结果

最后,概率 ans 就是满足条件的组合数与总组合数的比值 cnt / total,再将结果四舍五入到三位小数输出。

def solution(n, m, arrayN, arrayM):
    # Edit your code here
    a_counts = {0: 1}
    b_counts = {0: 1}

    # 更新a_counts分布
    for num in arrayN:
        new_counts = {}
        for val, count in a_counts.items():
            for j in range(1, num + 1):
                new_sum = val + j
                if new_sum in new_counts:
                    new_counts[new_sum] += count
                else:
                    new_counts[new_sum] = count
        a_counts = new_counts

    # 更新b_counts分布
    for num in arrayM:
        new_counts = {}
        for val, count in b_counts.items():
            for j in range(1, num + 1):
                new_sum = val + j
                if new_sum in new_counts:
                    new_counts[new_sum] += count
                else:
                    new_counts[new_sum] = count
        b_counts = new_counts

    # 计算满足条件的组合数和总组合数
    total = sum(a_count * b_count for a_count in a_counts.values() for b_count in b_counts.values())
    cnt = sum(a_count * b_count for a_sum, a_count in a_counts.items() for b_sum, b_count in b_counts.items() if b_sum < a_sum)
    
    # 返回概率,保留三位小数
    ans = cnt / total
    return round(ans, 3)


if __name__ == "__main__":
    # Add your test cases here

    print(solution(1, 3, [8], [2, 3, 4]) == 0.255)