丑数
丑数为仅有 2,3或5 的质因子的数。数列1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, … 展示了前11个丑数。按照惯例,其中包括1。给定一个数字n,请你找出第n个丑数。
首先,如何判断一个数是否为丑数?将这个数分别除以2、3、5的最大可能次幂,如果最终得到1,则为丑数。
因为丑数的质因子仅为2、3、5,丑数数列的数将会被分为三组:
- 1x2, 2x2, 3x2, 4x2, 5x2, …
- 1x3, 2x3, 3x3, 4x3, 5x3, …
- 1x5, 2x5, 3x5, 4x5, 5x5, …
每一个子数列都是丑数本身与2、3、5相乘。因此我们可以利用类似合并排序一样通过合并三个子数列来得到所有丑数。
-
声明丑数数列: ugly[n]
-
初始化第一个丑数: ugly[0] = 1
-
初始化三个子数列索引,指向子数列的第一个元素: i2 = i3 = i5 = 0
-
初始化三个下一个丑数的可能值:
next_multiple_of_2 = ugly[i2] * 2;
next_multiple_of_3 = ugly[i3] * 3;
next_multiple_of_5 = ugly[i5] * 5;
-
填充dp数组
import time
def getNthUglyNo(n):
ugly = [0] * n
ugly[0] = 1
i2 = i3 = i5 = 0
next_multiple_of_2 = 2
next_multiple_of_3 = 3
next_multiple_of_5 = 5
for i in range(1, n):
ugly[i] = min(next_multiple_of_2,
next_multiple_of_3,
next_multiple_of_5)
if ugly[i] == next_multiple_of_2:
i2 += 1
next_multiple_of_2 = ugly[i2] * 2
if ugly[i] == next_multiple_of_3:
i3 += 1
next_multiple_of_3 = ugly[i3] * 3
if ugly[i] == next_multiple_of_5:
i5 += 1
next_multiple_of_5 = ugly[i5] * 5
return ugly[-1]
# Driver code
time_start = time.time()
no = getNthUglyNo(150)
time_end = time.time()
print('150th ugly no is', no)
print('cost ', (time_end - time_start) * 1000, 'ms')
由于时间复杂度为O(n), 所以用时已经没办法打印出来了。
斐波那契数列
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …
用数学术语来描述:
Fn = Fn-1 + Fn-2
种子数:F0 = 0, F1 = 1
给定一个数n,求第n个斐波那契数
和上一题类似,由下往上构建dp数组
def getNthFiboNo(n):
Fibo = [0] * (n)
Fibo[0] = 0
Fibo[1] = 1
if n <= 1:
return Fibo[n]
for i in range(2, n):
Fibo[i] = Fibo[i - 2] + Fibo[i - 1]
return Fibo[-1]
no = getNthFiboNo(9)
print('9th fibonacci no is', no)
# 9th fibonacci no is 21
卡特兰数
有关卡特兰数的介绍,这篇讲得很清楚了,也是类似上面两题一样,构建dp数组。
def getNthCatalanNo(n):
if(n == 0 or n == 1):
return 1
catalan = [0] * n
catalan[0] = 1
catalan[1] = 1
for i in range(2, n):
for j in range(i):
catalan[i] += catalan[j] * catalan[i - j - 1]
return catalan[-1]
no = getNthCatalanNo(10)
print('10th catlan no is', no)
贝尔数
应用:给定n个元素的集合,该集合有几种子集合?
该问题的解为贝尔数(Bell Number),该数的递推方程为:
∑ k = 0 n S ( n , k ) \sum_{k=0}^{n}S(n, k) k=0∑nS(n,k)
S ( n + 1 , k ) = k ∗ S ( n , k ) + S ( n , k − 1 ) S(n+1, k) = k*S(n, k) + S(n, k-1) S(n+1,k)=k∗S(n,k)+S(n,k−1)
另一种方法为利用贝尔三角,构建二位dp数组求解
1
1 2
2 3 5
5 7 10 15
15 20 27 37 52
def bellNumber(n):
bell = [[0 for i in range(n+1)] for j in range(n+1)]
bell[0][0] = 1
for i in range(1, n+1):
bell[i][0] = bell[i-1][i-1]
for j in range(1, i+1):
bell[i][j] = bell[i-1][j-1] + bell[i][j-1]
return bell[n][0]
# Driver program
for n in range(6):
print('Bell Number', n, 'is', bellNumber(n))
二项式系数
二项式系数 C(n, k) 可以定义为 (1 + x)n 展开中 xk 的系数。
请你实现这个函数。
首先,分割子结构:
C ( n , k ) = C ( n − 1 , k − 1 ) + C ( n − 1 , k ) C(n, k) = C(n-1, k-1) + C(n-1, k) C(n,k)=C(n−1,k−1)+C(n−1,k)
C ( n , 0 ) = C ( n , n ) = 1 C(n, 0) = C(n, n) = 1 C(n,0)=C(n,n)=1
因此,重复子结构,构建dp数组:
def binomalCoef(n, k):
C = [[0 for i in range(k+1)] for i in range(n+1)]
for i in range(n+1):
for j in range(min(i, k)+1):
if j == 0 or j == i:
C[i][j] = 1
else:
C[i][j] = C[i-1][j-1] + C[i-1][j]
return C[n][k]
n = 5
k = 2
print('binomial coefficient (5, 2) is', binomalCoef(n, k))
排列系数
排列是指将给定集合的所有成员排列成一个序列的过程。 一组n个元素上的排列数为n的阶乘。
而P(n,k)表示的排列系数用于表示从一组n个元素中获得具有k个元素的有序子集的方式的数量。
实现该方法。
运用数学知识,该方法的求解方式为:
P ( n , k ) = n ( n − 1 ) ( n − 2 ) . . . ( n − k + 1 ) ( k < = n ) P(n, k) = n(n-1)(n-2)...(n-k+1) (k <= n) P(n,k)=n(n−1)(n−2)...(n−k+1)(k<=n)
即
P ( n , k ) = n ! ( n − k ) ! P(n, k) = \frac{n!}{(n-k)!} P(n,k)=(n−k)!n!
因此,
def permutationCoeff(n, k):
P = [[0 for i in range(k + 1)]
for j in range(n + 1)]
# 计算排列系数
# 由底至上
for i in range(n + 1):
for j in range(min(i, k) + 1):
# 初始值
if (j == 0):
P[i][j] = 1
else:
P[i][j] = P[i - 1][j] + (
j * P[i - 1][j - 1])
# 如果j小于k,则返回0
if (j < k):
P[i][j + 1] = 0
return P[n][k]
n = 10
k = 2
print("Value fo P(", n, ", ", k, ") is ",
permutationCoeff(n, k), sep = "")