leetcode算法学习(1)——计数质数:统计所有小于非负整数 n 的质数的数量

示例

输入: 10
输出: 4
解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。

思路:

质数就是除了 1 和本身找不到其他能除尽的数,思路请看题目的提示!

思路一:暴力法(超时)

for … else 的用法, 一般配合 break 使用

class Solution:
    def countPrimes(self, n: int) -> int:
        res = 0
        for i in range(2, n):
            for j in range(2, i):
                if i % j == 0:
                    break
            else:
                #print(i)
                res += 1
        return res

思路二:优化暴力(超时)

验证质数可以不需要小于它的数都验证
考虑12的所有因子:
2×6 = 12
3×4 = 12
4×3 = 12
6×2 = 12
如您所见,不需要进行4×3和6×2的计算。 因此,我们只需要考虑高达√n的因数,因为如果n可被某个数p整除,则n = p×q,并且由于p≤q,我们可以得出p≤√n。

class Solution:
    def countPrimes(self, n: int) -> int:
        res = 0
        for i in range(2, n):
            for j in range(2, int(i ** 0.5) + 1):
                if i % j == 0:
                    break
            else:
                # print(i)
                res += 1
        return res

思路三:厄拉多塞筛法

让我们看一下第一个数字2。我们知道2的所有倍数一定不能是素数,因此我们将它们标记为非素数。 然后,我们看下一个数字3。类似地,3的所有倍数(例如3×2 = 6、3×3 = 9 …)一定不能是素数,因此我们也将它们标记为非质数。 现在我们看下一个数字4,该数字已经被标记。 这告诉你什么? 您是否也应标记4的所有倍数?

class Solution:
    def countPrimes(self, n: int) -> int:
        isPrimes = [1] * n
        res = 0
        for i in range(2, n):
            if isPrimes[i] == 1: res += 1
            j = i
            while i * j < n:
                isPrimes[i * j] = 0
                j += 1
        return res

思路四:综上一起优化

4不是质数,因为它可以被2整除,这意味着4的所有倍数也必须被2整除并且已经被标记。 因此,我们可以立即跳过4并转到下一个数字5。现在,所有5的倍数,例如5×2 = 10、5×3 = 15、5×4 = 20、5×5 = 25,… 可以标记为 这里有一个小的优化,我们不需要从5×2 = 10开始。我们应该从哪里开始标记呢?
实际上,我们可以从5×5 = 25开始标记5的倍数,因为5×2 = 10已经被2的倍数标记了,类似地5×3 = 15已经被3的倍数标记了。因此, 如果当前数是p,我们总是可以标记出从p²开始标记的p的倍数,然后以p的增量标记:p² + p,p² + 2p,…现在终止循环条件是什么?
是的,终止环路条件可以是p <√n,因为所有非素数≥√n必须已经被标记。 循环终止时,表中所有未标记的数字均为质数。

class Solution:
    def countPrimes(self, n: int) -> int:
        if n < 2: return 0
        isPrimes = [1] * n
        isPrimes[0] = isPrimes[1] = 0
        for i in range(2, int(n ** 0.5) + 1):
            if isPrimes[i] == 1:
                isPrimes[i * i: n: i] = [0] * len(isPrimes[i * i: n: i])
        return sum(isPrimes)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值