📌  相关文章
📜  可以被给定的N位数字集(最多由0和7组成)的最大数,可以被50整除(1)

📅  最后修改于: 2023-12-03 14:50:38.284000             🧑  作者: Mango

可以被给定的N位数字集(最多由0和7组成)的最大数,可以被50整除

简介

在给定一个最多由0和7组成的长度为N的数字集合中,寻找最大的能够被50整除的数。

解决方法
方法1: 暴力枚举

首先,我们需要清楚一个性质:一个数能被50整除,当且仅当它能被10整除,并且它的个位上是0。于是,我们可以从高位到低位扫描这个数字集,每一位的选择只有0或者7,如果选择了7,则要求前面的数字模10余3,如果选择了0,则不限制前面数字的余数。最后得到的数一定是能被50整除的最大数。

时间复杂度:$O(2^N)$

方法2: 数学分析

如果一个数能被50整除,那么它一定能被10和25整除,所以我们只需要找一个长度为N的由0和7组成的序列,并且这个序列末尾连续的两个数字组成的数能被4整除(因为25能被4整除)即可。不妨假设这个序列的长度为k,那么我们只需要在这个序列中找到一个尽可能长的子序列,使得它末尾的两个数字组成的数能被4整除。对于长度为k的序列,末尾两个数能组成的数字共有8种,分别是00、04、07、14、17、20、24、27。我们可以用一个长度为8的桶记录每一种数字组合的最长子序列长度,然后从桶的末尾向前遍历,取长度最长的子序列作为答案。

时间复杂度:$O(N)$

代码实现
方法1: 暴力枚举
def max_num(N):
    if N == 1:
        return 0
    ans = -1
    for i in range(2 ** N):
        flag = True
        num = 0
        for j in range(N):
            if i & (1 << j):
                num = num * 10 + 7
                if num % 10 != 3:
                    flag = False
                    break
            else:
                num = num * 10
        if flag and num % 50 == 0:
            ans = max(ans, num)
    return ans
方法2: 数学分析
def max_num(N):
    if N == 1:
        return 0
    cnt = [0] * 8
    for i in range(2 ** N - 1, -1, -1):
        num = 0
        for j in range(N):
            if i & (1 << j):
                num = num * 10 + 7
            else:
                num = num * 10
        if num % 4 == 0:
            idx = (num % 100) // 10 * 4 + num % 4
            cnt[idx] = max(cnt[idx], bin(i).count('1'))
    ans = 0
    for i in range(8):
        if cnt[i] > 0:
            num = i // 4 * 10 + i % 4
            ans = ans * (2 ** cnt[i]) + num * (10 ** cnt[i])
    return ans
总结

两种方法分别适用于不同情况。当N比较小的时候,暴力枚举的时间复杂度并不高,可以使用方法1;当N比较大时,可以使用方法2进行数学分析,优化时间复杂度。