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 Macchiato2 小时前
Leetcode 3213. Construct String with Minimum Cost
动态规划·leetcode hard·trie树·leetcode 3213·leetcode周赛405
Espresso Macchiato7 天前
Leetcode 3203. Find Minimum Diameter After Merging Two Trees
leetcode hard·图算法·拓扑图·leetcode 3203·leetcode 周赛404
Espresso Macchiato14 天前
Leetcode 3193. Count the Number of Inversions
leetcode·动态规划·leetcode hard·leetcode 3193·leetcode双周赛133
Espresso Macchiato22 天前
Leetcode 3187. Peaks in Array
leetcode hard·leetcode周赛402·leetcode 3187·segment tree·分段树
程序猿 M22 天前
Integer溢出问题
java·二进制·integer·原码·补码
这是我581 个月前
算法家族之一——二分法
c语言·算法·visual studio·二分法
Jay 171 个月前
PolarCTF 2024夏季个人挑战赛 个人WP
web安全·密码学·逆向·二进制·ctf·misc·polar
緑水長流*z1 个月前
计算机基础(5)——进制与进制转换
二进制·进制转换·十六进制·计算机基础·十进制·进制运算
anlog1 个月前
c# 输出二进制字符串
开发语言·c#·二进制
ya888g1 个月前
信息学奥赛初赛天天练-15-阅读程序-深入解析二进制原码、反码、补码,位运算技巧,以及lowbit的神奇应用
二进制·位运算·信息学奥赛·原码·反码·补码