今天来讲讲剩下几块内容:素数,最大公约数,进制转换,阶乘.
素数
素数分解
每一个数都可以分解成素数的乘积,例如 84 = 2^2 * 3^1 * 5^0 * 7^1 * 11^0 * 13^0 * 17^0 * …
整除
令 x = 2^m0 * 3^m1 * 5^m2 * 7^m3 * 11^m4 * … 令 y = 2^n0 * 3^n1 * 5^n2 * 7^n3 * 11^n4 * …
如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。
x 和 y 的 最大公约数 为:gcd(x,y) = 2^min(m0,n0) * 3^min(m1,n1) * 5^min(m2,n2) * ...
x 和 y 的 最小公倍数 为:lcm(x,y) = 2^max(m0,n0) * 3^max(m1,n1) * 5^max(m2,n2) * ...
最大公约数
对于最大公约数问题,因为需要计算 a % b ,而这个操作是比较耗时的,可以利用减法和移位操作来替换它。
对于 a 和 b 的最大公约数 f(a, b),有:
1. 如果 a 和 b 均为偶数,f(a, b) = 2*f(a/2, b/2);
2. 如果 a 是偶数 b 是奇数,f(a, b) = f(a/2, b);
3. 如果 b 是偶数 a 是奇数,f(a, b) = f(a, b/2);
4. 如果 a 和 b 均为奇数,f(a, b) = f(a, a-b);
乘 2 和除 2 都可以转换为移位操作。
204. 计数质数
统计所有小于非负整数 n 的质数的数量。
示例:
输入: 10
输出: 4
解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
这题搜到一个非常牛逼的算法,叫做厄拉多塞筛法. 比如说求20以内质数的个数,首先0,1不是质数.2是第一个质数,然后把20以内所有2的倍数划去.2后面紧跟的数即为下一个质数3,然后把3所有的倍数划去.3后面紧跟的数即为下一个质数5,再把5所有的倍数划去.以此类推.
代码的实现上用了非常好的技巧:
def countPrimes(self, n: int) -> int:
if n < 3:
return 0
else:
# 首先生成了一个全部为1的列表
output = [1] * n
# 因为0和1不是质数,所以列表的前两个位置赋值为0
output[0],output[1] = 0,0
# 此时从index = 2开始遍历,output[2]==1,即表明第一个质数为2,然后将2的倍数对应的索引
# 全部赋值为0. 此时output[3] == 1,即表明下一个质数为3,同样划去3的倍数.以此类推.
for i in range(2,int(n**0.5)+1):
if output[i] == 1:
output[i*i:n:i] = [0] * len(output[i*i:n:i])
# 最后output中的数字1表明该位置上的索引数为质数,然后求和即可.
return sum(output)
在上面遍历索引的时候用到了一个非常好的技巧. 即i是从(2,int(n**0.5)+1)而非(2,n).这个技巧是可以验证的,比如说求9以内的质数个数,那么只要划掉sqrt(9)以内的质数倍数,剩下的即全为质数. 所以在划去倍数的时候也是从i*i开始划掉,而不是i+i.
这个解法真是太赞了!又学到了很多~~~ 和大家分享一下
504. 七进制数
给定一个整数,将其转化为7进制,并以字符串形式输出。
示例 1:
输入: 100
输出: "202"
示例 2:
输入: -7
输出: "-10"
注意: 输入范围是 [-1e7, 1e7] 。
class Solution(object):
def convertToBase7(self, num):
"""
:type num: int
:rtype: str
"""
A = []
if num == 0:
return "0"
if num < 0:
s = '-'
else:
s = ''
num = abs(num)
while(num > 0):
A.append(num % 7)
num = num // 7
A = A[::-1]
for i in A:
s = s + str(i)
return s
172. 阶乘后的零
给定一个整数 n,返回 n! 结果尾数中零的数量。
示例 1:
输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。
class Solution(object):
def trailingZeroes(self, n):
"""
:type n: int
:rtype: int
"""
if n < 5:
return 0
else:
m = 1
sum = 0
while n>= (5**m):
sum += n // (5**m)
m += 1
return sum
67. 二进制求和
给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字 1 和 0。
示例 1:
输入: a = "11", b = "1"
输出: "100"
示例 2:
输入: a = "1010", b = "1011"
输出: "10101"
方法一:
class Solution(object):
def addBinary(self, a, b):
return bin(int(a,2) + int(b,2))[2:]
方法二:
class Solution:
def addBinary(self, a: str, b: str) -> str:
# 短字符串前端补零,保证两者长度相等
if len(a) > len(b):
b = '0'* (len(a)-len(b)) + b
elif len(a) < len(b):
a = '0'* (len(b) - len(a)) + a
res, carry = '', '0'
for a_, b_ in reversed(list(zip(a, b))):
if a_ == '0' and b_ == '0': # 当前位两个数都是0
r = carry
carry = '0'
elif a_ == '1' and b_ == '0' or a_ == '0' and b_ == '1': # 当前位两个数不同
r = '1' if carry == '0' else '0'
carry = '1' if carry == '1' else '0'
else: # 当前位两个数都是1
r = '1' if carry == '1' else '0'
carry = '1'
res = r + res
if carry == '1': # 如果还有进位
res = '1' + res
return res
415. 字符串相加
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
注意:
num1 和num2 的长度都小于 5100.
num1 和num2 都只包含数字 0-9.
num1 和num2 都不包含任何前导零。
你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式。
class Solution(object):
def addStrings(self, num1, num2):
"""
:type num1: str
:type num2: str
:rtype: str
"""
l = max(len(num1),len(num2))
num1 = num1.zfill(l)
num2 = num2.zfill(l)
p = 0
r = ''
for i in range(l):
n1 = num1[l-i-1]
n2 = num2[l-i-1]
rr = int(n1) + int(n2) + p
p = rr // 10
r = str(rr%10) + r
if p:
r = '1' + r
return r
希望本文能对你有所帮助!
最后打个小广告,我的公众号,会写点学习心得,喜欢可以关注下!~!