Leetcode 3145. Find Products of Elements of Big Array

  • [Leetcode 3145. Find Products of Elements of Big Array](#Leetcode 3145. Find Products of Elements of Big Array)
    • [1. 解题思路](#1. 解题思路)
    • [2. 代码实现](#2. 代码实现)

1. 解题思路

这道题思路上还是比较直接的,就是实现上非常的繁琐,着实花了不少力气。

显然,这道题本质上就是要实现一个快速的query(i, j, k)函数,可以求出big array当中i到j位置当中所有元素的积对于k的模。

而这个,我们就可以拆分为以下一个问题:

  • 定义函数count(i)来对于1到i个位置所有的二的指数出现的次数来进行计数。

此时,我们就可以快速得到query(i, j, k)函数的伪代码实现如下:

python 复制代码
def query(i, j, k):
    cnt1 = count(i-1)
    cnt2 = count(j)
    ans = 1
    for p, v in cnt2.items():
        # p为2的指数
        ans = ans * pow(p, v) % k
    return ans

因此,我们的问题就有转换为了如何实现这个count函数。

对于这个问题,我们将其进一步拆分为以下两个问题:

  • 坐标位置i对应的整数为多少?
  • 对于任意整数n,将1到n拆分为big array之后其中包含的所有2的指数出现的次数是多少?

对于后者,我们将n写作二进制数,然后看从 2 p 2^p 2p一共出现了多少次就只需要找到不大于n的第一个p位置上为1的数,然后将第p个位置抽走,此时剩下的的位上表示的数字k加1就是一共出现了多少次(0-k)。比如5,写作二进制就是101,此时对于1到5,出现的1的个数就是3(2(10)+1),出现的2的个数就是2(1(1)+1),出现的4的个数就是2(1(01)+1)。

这样,我们就可以很快地求得对任意整数n,从1到n当中出现过的2的指数的个数,此时,我们将其相加即可得到从1到n组成的big array的元素个数,因此,通过二分法,我们又可以快速回答1中的问题,即对于任意坐标i,它对应的整数是多少。

综上,我们就对上述问题进行了完整的回答。思路上还是比较简单清晰的,不过实现上......

诸君,自求多福吧,反正我是被折磨得够呛......

2. 代码实现

给出python代码实现如下:

python 复制代码
class Solution:
    def findProductsOfElements(self, queries: List[List[int]]) -> List[int]:
        
        @lru_cache(None)
        def power(i, k, mod):
            if i==1 or k == 0:
                return 1
            elif k == 1:
                return i % mod
            return (power(i, k//2, mod) * power(i, k-k//2, mod)) % mod
        
        @lru_cache(None)
        def num2digits(n):
            return tuple([int(x) for x in bin(n)[2:][::-1]])
        
        def digits2num(digits):
            num = 0
            for d in digits[::-1]:
                num = num * 2 + d
            return num

        @lru_cache(None)
        def count_power(n, k):
            digits = list(num2digits(n))
            if k >= len(digits):
                return 0
            if digits[k] == 0:
                i = 0
                while i < k:
                    digits[i] = 1
                    i += 1
                while digits[i] == 0:
                    digits[i] = 1
                    i += 1
                digits[i] = 0
            digits.pop(k)
            return digits2num(digits) + 1
        
        @lru_cache(None)
        def get_big_num_end_index(num):
            ans = 0
            k = 0
            while True:
                cnt = count_power(num, k)
                if cnt == 0:
                    break
                ans += cnt
                k += 1
            return ans
        
        @lru_cache(None)
        def _count(idx, k):
            i, j = 0, idx+1
            while j-i > 1:
                m = (i+j) // 2
                cnt = get_big_num_end_index(m)
                if cnt <= idx:
                    i = m
                else:
                    j = m
            loc = get_big_num_end_index(i)
            r = idx-loc
            digits_j = num2digits(j)
            extra = 1 if len(digits_j) > k and digits_j[k] == 1 and sum(digits_j[:k+1]) <= r else 0
            return count_power(i, k) + extra
        
        @lru_cache(None)
        def count(idx):
            if idx == 0:
                return defaultdict(int)
            cnt = defaultdict(int)
            k = 0
            while True:
                c = _count(idx, k)
                if c == 0:
                    break
                cnt[k] = c
                k += 1
            return cnt
        
        @lru_cache(None)
        def query(i, j, mod):
            if i == 0:
                cnt1 = defaultdict(int)
            else:
                cnt1 = count(i-1)
            cnt2 = count(j)
            ans = 1
            p, k = 1, 0
            while cnt2[k] > 0:
                c = cnt2[k] - cnt1[k]
                ans = (ans * power(p, c, mod)) % mod
                p = (p * 2) % mod
                k += 1
            return ans
            
        return [query(i+1, j+1, mod) for i, j, mod in queries]

提交代码评测得到:耗时7624ms,占用内存662.3MB。

相关推荐
Espresso Macchiato4 天前
Leetcode 3729. Count Distinct Subarrays Divisible by K in Sorted Array
leetcode·leetcode hard·容斥原理·leetcode 3729·leetcode周赛473·前序和数组
楠木s12 天前
ctfshow pwn44
linux·服务器·网络·安全·网络攻击模型·二进制
Espresso Macchiato15 天前
Leetcode 3715. Sum of Perfect Square Ancestors
算法·leetcode·职场和发展·leetcode hard·树的遍历·leetcode 3715·leetcode周赛471
Espresso Macchiato19 天前
Leetcode 3710. Maximum Partition Factor
leetcode·职场和发展·广度优先遍历·二分法·leetcode hard·leetcode 3710·leetcode双周赛167
笔沫拾光21 天前
二进制世界如何表达现实世界的文字、图像和视频
计算机·二进制
深思慎考25 天前
Linux二进制查看工具——hexdump
linux·c++·二进制·文件查看·hexdump
Espresso Macchiato1 个月前
Leetcode 3700. Number of ZigZag Arrays II
动态规划·leetcode hard·矩阵乘法·leetcode 3700·leetcode周赛469
Espresso Macchiato1 个月前
Leetcode 3695. Maximize Alternating Sum Using Swaps
并查集·leetcode hard·dsu·uf·leetcode 3695·leetcode双周赛166
KarrySmile2 个月前
HOT100--Day23--153. 寻找旋转排序数组中的最小值,4. 寻找两个正序数组的中位数,20. 有效的括号
二分查找·数组··hot100·二分法·二分搜索·旋转排序数组
程序猿编码3 个月前
二进制签名查找器(Aho-Corasick 自动机):设计思路与实现原理(C/C++代码实现)
c语言·c++·网络安全·二进制·逆向工程·ac自动机