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。

相关推荐
centos089 小时前
PWN(栈溢出漏洞)-原创小白超详细[Jarvis-level0]
网络安全·二进制·pwn·ctf
玉蜉蝣5 天前
PAT甲级-1048 Find Coins
c++·算法·二分法
Tisfy9 天前
LeetCode 3211.生成不含相邻零的二进制字符串:二进制枚举+位运算优化
算法·leetcode·二进制·题解·枚举·位运算
vortex514 天前
安全见闻(9)——开阔眼界,不做井底之蛙
安全·网络安全·逆向·二进制·1024程序员节
Espresso Macchiato25 天前
Leetcode 3321. Find X-Sum of All K-Long Subarrays II
leetcode·滑动窗口·leetcode hard·leetcode 3321·leetcode周赛419
ShuQiHere2 个月前
【ShuQiHere】 进制转换的世界:从十进制到二进制、十六进制的转换技巧
二进制·计算机组成
Jay 172 个月前
第四届“长城杯”网络安全大赛 暨京津冀网络安全技能竞赛(初赛) 全方向 题解WriteUp
安全·web安全·密码学·二进制·ctf·长城杯·安全杂项
小妖剑2 个月前
位运算:带带孩子吧,孩子很强的!
c++·性能优化·二进制·位运算·cpp
万河归海4282 个月前
C语言——利用二分法求数组中特定元素的索引,并在函数中引入了冒泡排序,可以求无序数组中的特定元素的索引
c语言·数据结构·算法·visualstudio·数组·二分法·冒泡
无 双2 个月前
BUUCTF PWN wp--jarvisoj_level0
网络安全·二进制·ctf pwn