Python数据结构与算法--数组--洗牌问题+质数问题+验证哥德巴赫猜想

洗牌问题:洗牌后的每个元素随机出现在每个位置,且概率相同

Fisher-Yates 洗牌算法(也被称为 Knuth 洗牌算法)。

这个算法的工作原理是,从第一张牌开始,对于每一张牌,从当前位置到最后一张牌之间随机选择一张牌,并与当前牌进行交换。这样,每一种可能的排列都有相等的概率。

这个算法的优点是,它产生的结果是均匀的,即所有的排列都有相等的概率。并且,每张牌只被交换一次,所以这个算法是高效的。

import random
def shuffle_correct(cards):
    for i in range(len(cards)):
        k=random.randint(i,len(cards)-1)#生成一个未交换过的卡牌(i之前的都已经交换过了,不需要在动了)
        cards[i],cards[k]=cards[k],cards[i]#交换卡牌

质数问题

"厄拉多塞筛法"(Sieve of Eratosthenes)的算法来解决。厄拉多塞筛法是一种用于查找所有小于给定数的质数的有效方法。

以下是算法的步骤:

1.创建一个长度为 n+1 的布尔数组(默认所有值都为 True),表示所有的数初步都被认为是质数。

2.对于每一个数 i,从 2 开始,到  \sqrt{n}结束:

找出非素数,并将其设置为False:如果数组中的第 i 个元素是 True,那么就遍历从 i^{2} 开始,到 n 的所有 i 的倍数的元素,将其设为 False(素数的倍数都不是素数,表示这些数不是质数,因为它们都可以被 i 整除)。在这个过程结束后,数组中仍然为 True 的元素就对应着是质数的数。计数这些元素的数量,就是结果。

def count_prime(n):
    if n < 2:
        return 0
    isPrime = [1] * (n+1)
    isPrime[0] = isPrime[1] = 0
    for i in range(2, int((n)**0.5) + 1):
        if isPrime[i]:#此时要把所有i的倍数都赋值为零,本来算法应该是从0开始的,这里优化了,从i*i开始赋值
            isPrime[i*i: n+1: i] = [0] * len(isPrime[i*i: n+1: i])#一次性把所有i的倍数都赋值为零
    return sum(isPrime)

为什么是 isPrime[𝑖^2: n+1: i] = [0] * len(isPrime[𝑖^2: n+1: i]),从𝑖^2开始呢 因为在算法执行到这一步时,小于 (i) 的所有质数的倍数已经在前面的步骤中被标记为非质数(即0)了。 更具体地说,假设当前的数是 (i),那么 (i) 的所有小于 (i) 的倍数(如 (2i, 3i, ……, (i-1)i))都已经在处理 (2, 3, ……, i-1) 时被处理过了。 从i*i开始可以避免一些不必要的计算,提高算法的效率。

通过一个具体的例子来解释。 假设当前的数是4,那么在我们处理4之前,我们已经处理过2和3了。当处理2时,我们将所有2的倍数(包括4、6、8等)标记为非质数。因此,当我们处理到4时,4的所有小于4的倍数(即2×4)已经被标记为非质数了。 同样,当我们处理3时,我们将所有3的倍数(包括6、9等)标记为非质数。因此,当我们处理到4时,所有小于4且是4的倍数的数(即3×4)也已经被标记为非质数了。 因此,对于4,我们只需要从 (4×4=16) 开始标记,而不需要从 (2×4)(2×4) 或 (3×4)(3×4) 开始。这样可以避免一些不必要的计算,提高算法的效率

第二种代码的实现

def count_prime(n):
    is_prime = [True] * (n + 1)
    i = 2
    while (i * i <= n):#在根号n之前一定存在素数
        if (is_prime[i]):#找到素数
            j = i#开始标记素数的倍数,从i*i开始
            while (j * i <= n):#寻找n之前的非素数
                is_prime[i * j] = False#将所有倍数都标记为False--非素数
                j += 1
        i += 1
        
    count = 0
    for i in range(2, n+1):
        if (is_prime[i]):
            count += 1
            print(i, end = " ")
            
    return count
        


验证哥德巴赫猜想

任一大于2的偶数,都可表示成两个质数之和。

def verifyGoldbach_v2(n):
    def getPrimes(n):
        isPrime = [1] * (n+1)
        isPrime[0] = isPrime[1] = 0
        for i in range(2, int((n)**0.5) + 1):
            if isPrime[i]:
                isPrime[i*i: n+1: i] = [0] * len(isPrime[i*i: n+1: i])
        #到这里和上面寻找质数列表的过程一模一样,不过接下来是将质数的布尔列表转化为对应的质数列表
        primes = [i for i, prime in enumerate(isPrime) if prime]
        return primes

    primes = getPrimes(n)#得到质数组成的列表
#使用双指针
    for even in range(4, n+1, 2):
        left, right = 0, len(primes) - 1
        while left <= right:
            if primes[left] + primes[right] == even:
                break
            elif primes[left] + primes[right] < even:
                left += 1
            else:
                right -= 1
        else:
            return False
    return True

第二种实现代码

def goldbach(n):
    is_prime = [True] * (n + 1)
    i = 2
    while (i * i <= n):
        if (is_prime[i]):
            j = i
            while (j * i <= n):
                is_prime[i * j] = False
                j += 1
        i += 1
    #把素数列表算出来    
    count = 0
    for i in range(2, n+1):
        if (is_prime[i]):
            count += 1
            
    primes = [None] * count
    idx = 0
    for i in range(2, n + 1):#通过列表得到索引值列表
        if (is_prime[i]):#如果是素数,就把所有的1变成索引值
            primes[idx] = i
            idx += 1
    
    left = 0
    right = count - 1
    while (left < right):
        if (n == primes[left] + primes[right]):
            print(n," = ", primes[left], " + ", primes[right])
            left += 1
            right -= 1
        elif (n > primes[left] + primes[right]):
            left += 1
        else:
            right -= 1

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隔叶听风˗ˋˏ ˎˊ˗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值