质数、因数、最大公约数经典问题整理
1、计数质数
MX = 5000000 is_prime = [1] * MX is_prime[0] = is_prime[1]= 0 for i in range(2, MX): if is_prime[i]: for j in range(i * i, MX, i): is_prime[j] = 0 class Solution: def countPrimes(self, n: int) -> int: return sum(is_prime[:n])
class Solution: def countDifferentSubsequenceGCDs(self, nums: List[int]) -> int: ans, mx = 0, max(nums) has = [False] * (mx + 1) for x in nums: has[x] = True for i in range(1, mx + 1): g = 0 # 0 和任何数 x 的最大公约数都是 x for j in range(i, mx + 1, i): # 枚举 i 的倍数 j if has[j]: # 如果 j 在 nums 中 g = gcd(g, j) # 更新最大公约数 if g == i: # 找到一个答案(g 无法继续减小) ans += 1 break # 提前退出循环 return ans
利用子数组gcd值为有限个的情况(复杂度为lgn),对每个gcd值使用最大长度数组进行匹配
class Solution: def maxGcdSum(self, nums: List[int], k: int) -> int: maxl = 0 pre = [0] for num in nums: pre.append(pre[-1] + num) g = deque() for i, num in enumerate(nums): temp, s, si = deque(), num, i while g: n2, j = g.pop() if gcd(n2, s) < s: temp.appendleft((s, si)) if i - si + 1 >= k: maxl = max(maxl, (pre[i + 1] - pre[si]) * s) s, si = gcd(n2, s), j else: si = j else: temp.appendleft((s, si)) if i - si + 1 >= k: maxl = max(maxl, (pre[i + 1] - pre[si]) * s) g = temp return maxl
找到最接近目标值的函数值 与上述做法类似,利用子数组与运算结果为有限个(lgn)的性质,代码如下:
class Solution: def closestToTarget(self, arr: List[int], target: int) -> int: ans = abs(arr[0] - target) valid = {arr[0]} for num in arr: valid = {x & num for x in valid} | {num} ans = min(ans, min(abs(x - target) for x in valid)) return ans
class Solution: def kthFactor(self, n: int, k: int) -> int: count = 0 factor = 1 while factor * factor <= n: if n % factor == 0: count += 1 if count == k: return factor factor += 1 factor -= 1 if factor * factor == n: factor -= 1 while factor > 0: if n % factor == 0: count += 1 if count == k: return n // factor factor -= 1 return -1
5、分解质因数 -- 分割数组使乘积互质
class Solution: def findValidSplit(self, nums: List[int]) -> int: left = {} # left[p] 表示质数 p 首次出现的下标 right = [0] * len(nums) # right[i] 表示左端点为 i 的区间的右端点的最大值 def f(p: int, i: int) -> None: if p in left: right[left[p]] = i # 记录左端点 l 对应的右端点的最大值 else: left[p] = i # 第一次遇到质数 p for i, x in enumerate(nums): d = 2 while d * d <= x: # 分解质因数 if x % d == 0: f(d, i) x //= d while x % d == 0: x //= d d += 1 if x > 1: f(x, i) max_r = 0 for l, r in enumerate(right): if l > max_r: # 最远可以遇到 max_r return max_r # 也可以写 l-1 max_r = max(max_r, r) return -1
使用前缀和 -- 向下取整数对和、 统计美丽子字符串 II
class Solution: def countPairs(self, nums: List[int], k: int) -> int: mx = max(max(nums), k) cnt = [0] * (mx + 1) for num in nums: cnt[num] += 1 #统计每个数的倍数出现的次数 for i in range(1, mx + 1): for j in range(2 * i, mx + 1, i): cnt[i] += cnt[j] res = 0 for num in nums: res += cnt[k // gcd(k, num)] for num in nums: if num * num % k == 0: res -= 1 return res // 2