洗牌问题:洗牌后的每个元素随机出现在每个位置,且概率相同
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 开始,到 结束:
找出非素数,并将其设置为False:如果数组中的第 i 个元素是 True,那么就遍历从 开始,到 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