质数、因数、最大公约数经典问题整理

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])

2、序列中不同最大公约数的数目

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

 3、子数组的最大 GCD-Sum

利用子数组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

4、n 的第 k 个因子

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

6、统计可以被 K 整除的下标对数目

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

  

posted on 2024-04-27 15:36  sw-lab  阅读(6)  评论(0编辑  收藏  举报

导航