素因子 质因数 第k个数问题

当某个数的素因子只包括a,b,c时,意味着这个数可以拆分成 ax1 * bx2 * cx3 也就是若干个a若干个b若干个c相乘后再相乘,比如下面这一题:
M17.09 第k个数
这一类题目普遍有两种做法,一是堆,二是动态规划
归根结底,第k个数一定是前面的k-1个数中的某个数 *a 或 *b 或 *c 得到的,具体是哪一个数乘以几得到的其实是要一个个算的,最暴力的方法就是每一次算第k个数的时候就对前面k-1个数分别×素因数,取出第一个大于第 k-1 个数的数,他就是第k个数,一个个的算直到找到答案,代码如下:

暴力:

    # 这种解法非常耗时
    def getKthMagicNumber(self, k: int) -> int:
        al_nums = [1]
        while k-1:
        # 使用set去重
            t = set()
            for i in al_nums:
                t.add(i * 3)
                t.add(i * 5)
                t.add(i * 7)
            t = list(t)
            t.sort()
            index = bisect_left(t, al_nums[-1])
            if t[index] == al_nums[-1]:
                index += 1
            al_nums.append(t[index])
            k -= 1
        return al_nums[-1]

方法一、堆

上面的暴力解法中,每一次都是从头算,从而浪费了大量的时间,其实可以反着算,算开头的那个数,比如,开始时是1,将1乘以3,5,7得到 [1,3,5,7]那么第一个数就是1,后面的数不可能由1×3,5,7得到了,所以将1踢出去(其实是将1记作第一个数,我们要找的是第k个数),将3乘以3,5,7得到9,15,21,加入堆得到 [3,5,7,9,15,21],后面的数不可能再由3乘3,5,7得到了,所以将3踢出去(这就是最终答案的第2个数,我们要求第k个数),然后对5进行同样的操作并踢出去,直到踢到第k个数就是答案,由于这个数组需要始终保证最小的数在开头并且会被不断地踢出去,所以要用到堆!

三叶姐的解析

def getKthMagicNumber(k: int):
    q, vis = [1], set()
    while k:
        # 这个t就是前面最小的从来没有乘过的数
        t = heapq.heappop(q)
        k -= 1
        if k == 0:
            return t
        vis.add(t)
        for i in [3, 5, 7]:
            if t * i not in vis:
                heapq.heappush(q, t * i)
                vis.add(t * i)
    return -1

方法二:动态规划

其实,上面的解析也能看出来,第k个数是通过前面的k-1个数生成的,换句话说第k个数与前面的数有着非常紧密的关系,这不就是动态规划吗!第k个数会由前面k-1个数中的某一个数乘3或乘5或乘7得到,那么关键就是哪一个数乘以几的问题,动态规划解决的就是这个问题

由于可能是某一个数乘以3,5,7得到,所以记录三个位置,p3,p5,p7分别表示要乘3,5,7的值的位置,刚开始时这三个位置都在1处,然后每一次循环就将这三个(初始在同一个地方)乘以对应的值,判断哪一个值是最小的,将这个最小的记下来,并将得到这个最小值的指针加一其他的指针不动,一直循环下去,这样每一个值都会乘三个质因数各一次,且不断地涨,所以正确

def getKthMagicNumber(k: int):
    ans = [0] * k
    ans[0] = 1
    q3, q5, q7 = 0, 0, 0
    for i in range(1, k):
        t = min(ans[q3] * 3, ans[q5] * 5, ans[q7] * 7)
        ans[i] = t
        if t == ans[q3] * 3:
            q3 += 1
        if t == ans[q5] * 5:
            q5 += 1
        if t == ans[q7] * 7:
            q7 += 1
    return ans[-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值