python Solution LeetCode No.204 count-primes(计数质数)

题目:

统计所有小于非负整数 的质数的数量。

示例:

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

代码1:

class Solution:
    def countPrimes(self, n):
        if n <= 2:
            return 0
        else:
            countprimes = n//2
            for i in range(3, n, 2):
                if i == 3 or i == 5 or i == 7:
                    continue
                else:
                    sqrt_i = int(i ** 0.5)
                    for j in range(3, sqrt_i+1, 2):
                        if i % j == 0:
                            countprimes -= 1
                            break
        return countprimes

结果1:

代码2:

class Solution:
    def countPrimes(self, n):
        if n <= 2:
            return 0
        else:
            nlist = [1] * n
            nlist[:2:] = [0] * 2
            nlist[4::2] = [0] * len(nlist[4::2])
            sqrt_n = int(n ** 0.5)
            for j in range(3, sqrt_n+1, 2):
                nlist[j*j::j*2] = [0] * len(nlist[j*j::j*2])
            numprimes = nlist.count(1)
        return  numprimes

结果2:

 说明:

1.代码1是比较常规的解法,根据质数的定义0和1即不是质数也不是合数,而大于2的偶数一定是合数,所以提前进行了奇偶处理,countprimes = n//2取得小于n的所有奇数,其中包含1,不包含2,而2是质数,1和2相互抵消,所以既是奇数又可能是质数的总计数量为n//2。第一重循环在所有奇数内进行,起始值为3,以步进2递增,直到给定的targetnum(n),并计算每个奇数的平方根,因为每个奇数的两个质因数在它的平方根处相遇(质因数一定是一大一小,在平方根处附近相遇),就可以认为查找了该奇数的所有可能质因数。又由于不是所有奇数开平方后都是整数,所以使用sqrt_i = int(i ** 0.5)取整。第二重循环同样从3开始,步进为2(不干偶数什么事),循环上限为当前i的平方根+1,因为有些奇数是可以开平方得到整数,+1是为了将其平方的情况包含在内。当i能被j整除时,则可以肯定其为合数,从总体的countprimes减1,并且break第二重循环。所有循环执行完成后,剩余countprimes即为所求解。

但是代码1的执行效率很低,时间复杂度为O(n/2平方的),由于不用开辟其他任何新数据结构,其内存消耗非常小

2.代码2的解法不是太容易想到,核心原理是开辟新列表进行质数的标记,再统计列表得到大小。耗费了额外的空间,节省了一重循环,属于空间换时间的方法。首先初始化一个长度为n的列表,将所有值置1,表示默认所有元素都是质数,后续将0,1和大于2的元素置为0,刨去部分非质数,这里需要注意一下列表切片赋值的操作,nlist[4::2] = [0] * len(nlist[4::2])中,nlist[4::2]相当于切到了大于2的所有偶数的一个子列表,然后计算其长度,在将[0]这个值重复n次组成一个所有值为0的新列表,将原列表下标满足nlist[4::2]的元素全部置0。nlist[j*j::j*2] = [0] * len(nlist[j*j::j*2])这句其实是以j为步进遍历列表,其遍历过的所有值都能为j整除所以肯定是合数将其置0即可,以j*j作为起始值意在去重,因为(j-2)*j已经在前面计算过了,有点递推的意思。由于开始去除了偶数的干扰,所以这里的实际步进是j*2,最后统计一下列表中还剩多少个1,即为本题的解。

ps:nlist[j*j::j*2] = [0] * len(nlist[j*j::j*2])这句不是太好解释,可以手动打印j为3,5,7的情况,看结果比较直观。

由于减少了一重循环,执行效率较方法1高很多,多开了一个list,牺牲了部分空间。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值