由m种数字组成的n位数有多少个

知乎链接

问题描述

我和我女朋友的QQ号都是九位数字,这九个数字是有七个不同的数字组成的,我想问这种概率是多大,我们是不是特别我看缘分呢?求大神给算一下概率!

思路

定义问题:由7种数字组成的9位数一共有多少个?记做x,则答案为$frac{x2}{C_{10}7 imes C_{10}^{18}}$

所以关键在于由7种数字组成的9位数一共有多少个

from collections import Counter

from scipy.special import comb as c, factorial as f

"""
我和我女朋友的QQ号都是九位数字,而这九个数字完全相同只是数字顺序不同,这九个数字是有七个不同的数字组成的,我想问这种概率是多大
"""


def split(n, m):
    """
    整数拆分,把整数n拆成m个整数之和的形式
    :param n:
    :param m:
    :return:
    """
    if m == 0: return
    a = [1] * m
    a[-1] = n - (m - 1)
    yield a

    def can_increase(i):
        # i是否有增长空间
        if i == m - 1: return False
        for j in range(i + 1, m):
            if a[j] - a[i] > 1:
                return True
        return False

    while 1:
        # 首先找到最后一个增长点
        i = m - 1
        while i >= 0 and not can_increase(i):
            i -= 1
        # 如果没有增长点,直接退出
        if i == -1:
            break
        # 增长点增长,并且更改后续数组
        a[i] += 1
        for j in range(i + 1, m):
            a[j] = a[i]
        a[-1] = n - sum(a[:-1])
        yield a


def g(n, m):
    """
    由m个正整数组成的n位数有多少个
    :param n:
    :param m:
    :return:
    """
    s = 0
    for i in split(n, m):
        number_left = m
        position_left = n
        now = c(10, m)
        for j in i:
            now *= number_left * c(position_left, j)
            position_left -= j
            number_left -= 1
        for j in Counter(i).values():
            now /= f(j)
        s += now
    return s


def test():
    for i in range(1, 15):
        s = 0
        for j in range(i + 1):
            s += g(i, j)
        if s != 10 ** i:
            raise Exception("error {} {} {}".format(i, s, 10 ** i))


def find_rule():
    ma = 30
    table = [[0] * ma for _ in range(ma)]
    for i in range(1, ma):
        for j in range(1, i + 1):
            table[i][j] = g(i, j)
    for i in range(1, ma):
        for j in range(1, i + 1):
            print("%-8d" % (table[i][j] / table[i - 1][j]) if i > 1 and table[i - 1][j] else table[i][j], end=' ')
        print()
    for i in range(1, ma):
        for j in range(1, i + 1):
            print("%-8d" % table[i][j], end=' ')
        print()


test()
print(g(9, 7) ** 2 / c(10, 7) / 10 ** 18)
find_rule()

上述程序求解复杂度较高,实际上可以找到规律。用找到的规律可以飞快解决:由m种数字组成的n位数一共有多少种这种问题。

我找到的规律如下:
1、对于10进制来说,由11种数字组成的n位数个数为0,因为总共就10种数字,也就是说,整个表格只有前10列不为零
2、对于每列来说,最终都会变成等比数列,第i列的公比就是i
3、从左上角到右下角的斜线,呈现9、8、7、6、5、4、3、2、1、0的比例

原文地址:https://www.cnblogs.com/weiyinfu/p/9385565.html