leetcode
leetcode 2101 ~ 2150
二的幂数组中查询范围内的乘积

二的幂数组中查询范围内的乘积

难度:

标签:

题目描述

代码结果

运行时间: 97 ms, 内存: 42.1 MB


// Java Stream solution
// 思路:
// 1. 找到最小数量的2的幂次表示n
// 2. 使用Java Stream API简化查询处理和乘积计算

import java.util.*;

public class SolutionStream {
    private static final int MOD = 1000000007;

    public static List<Integer> findPowers(int n) {
        List<Integer> powers = new ArrayList<>();
        int power = 1;
        while (n > 0) {
            if ((n & 1) == 1) {
                powers.add(power);
            }
            n >>= 1;
            power *= 2;
        }
        return powers;
    }

    public static int[] getQueryResults(int n, int[][] queries) {
        List<Integer> powers = findPowers(n);
        return Arrays.stream(queries)
                .mapToInt(q -> {
                    return (int) Arrays.stream(powers.subList(q[0], q[1] + 1))
                            .mapToLong(Integer::longValue)
                            .reduce(1, (a, b) -> (a * b) % MOD);
                })
                .toArray();
    }

    public static void main(String[] args) {
        int n = 15;
        int[][] queries = {{0, 1}, {2, 2}, {0, 3}};
        int[] results = getQueryResults(n, queries);
        System.out.println(Arrays.toString(results)); // 输出: [2, 4, 64]
    }
}

解释

方法:

题解的思路是首先找出n的二进制表示中所有的1所对应的幂,将这些幂存入power数组中。接着,构建一个二维数组res,用于存储所有可能的查询区间[l, r]内的幂的乘积。最后,对于每个查询,直接从res数组中取出对应的结果。

时间复杂度:

O((log n)^2 + q)

空间复杂度:

O((log n)^2)

代码细节讲解

🦆
为什么在寻找powers数组时,选择使用二进制表示中1的位置对应的幂?这种方法和直接生成2的幂次方有什么不同?
在二进制中,一个数n的表示包含了这个数由2的幂次相加而成的具体信息。例如,n=5在二进制中表示为101,这意味着它可以表示为2^0 + 2^2。使用二进制表示中1的位置对应的幂可以直接得到组成n的2的幂次,这是针对具体数n的优化存储方式。与直接生成2的幂次方列表不同,这种方法只生成那些实际上在数n的二进制表示中出现的幂次,从而节省空间并直接定位到相关幂次,避免不必要的计算和存储。
🦆
题解中提到构建res数组用于存储所有可能的查询区间内的幂的乘积,这种方法是否存在内存效率低下的问题,特别是当n较大时?
确实,构建res数组来存储所有可能的查询区间[l, r]内的幂的乘积可能会导致内存效率低下,尤其是当n较大时。由于res是一个二维数组,其大小为幂次数组长度的平方,因此当幂数组长度较大时,所需的存储空间会快速增加。对于大规模数据或更长的幂次链,这种方法会占用大量内存,可能导致内存溢出或性能问题。在实际应用中,可能需要考虑更高效的数据结构或算法,如使用线段树或者懒惰传播等技术进行优化。
🦆
在计算乘积时,题解使用了取模操作,这是基于什么原因?是否考虑到了整数溢出的问题?
题解中使用取模操作的主要原因是为了防止整数溢出和保持计算结果的稳定性。由于连乘的结果可能非常大,超过了常规整型变量可以存储的范围,因此使用取模操作来确保结果不会溢出并且能够保持在一个安全的数值范围内。取模操作也确保了结果符合题目设定的约束条件(例如MOD = 10**9 + 7),这是编程竞赛和算法实现中常用的技术,用以处理大数的乘法运算问题。

相关问题