二的幂数组中查询范围内的乘积
说在前面
🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是出于什么原因,算法学习需要持续保持。
题目描述
给你一个正整数?n?,你需要找到一个下标从?0?开始的数组?powers?,它包含 最少?数目的 2?的幂,且它们的和为?n?。powers?数组是?非递减?顺序的。根据前面描述,构造?powers?数组的方法是唯一的。
同时给你一个下标从 0?开始的二维整数数组?queries?,其中?queries[i] = [lefti, righti]?,其中?queries[i]?表示请你求出满足?lefti <= j <= righti?的所有?powers[j]?的乘积。
请你返回一个数组?answers?,长度与?queries?的长度相同,其中?answers[i]是第?i?个查询的答案。由于查询的结果可能非常大,请你将每个?answers[i]?都对?109 + 7?取余?。
示例 1:
输入:n = 15, queries = [[0,1],[2,2],[0,3]]
输出:[2,4,64]
解释:
对于 n = 15 ,得到 powers = [1,2,4,8] 。没法得到元素数目更少的数组。
第 1 个查询的答案:powers[0] * powers[1] = 1 * 2 = 2 。
第 2 个查询的答案:powers[2] = 4 。
第 3 个查询的答案:powers[0] * powers[1] * powers[2] * powers[3] = 1 * 2 * 4 * 8 = 64 。
每个答案对 109 + 7 得到的结果都相同,所以返回 [2,4,64] 。
示例 2:
输入:n = 2, queries = [[0,0]]
输出:[2]
解释:
对于 n = 2, powers = [2] 。
唯一一个查询的答案是 powers[0] = 2 。答案对 10^9 + 7 取余后结果相同,所以返回 [2] 。
提示:
- 1 <= n <= 10^9
- 1 <= queries.length <= 10^5
- 0 <= starti <= endi < powers.length
思路分析
首先我们要先理解一下题目的意思,题目会给我们一个正整数?n?,我们需要找到一个下标从?0?开始的数组?powers?,它包含 最少?数目的 2?的幂,且它们的和为?n。得到powers数组之后,我们需要根据给出的二维整数数组?queries 进行相应的计算,其中?queries[i] = [lefti, righti]?,我们需要求出满足?lefti <= j <= righti?的所有?powers[j]?的乘积。
- 1、获取powers数组
powers数组需要满足以下两个条件
- 它包含 最少?数目的 2?的幂
- 它们的和为?n?
所以我们可以先找出小于等于n的所有正整数
const powList = [];
let num = 1;
while(num <= n){
powList.push(num);
num *= 2;
}
优先取powList
中的最大值,这样可以用最少数目的整数来组成powers
数组
let ind = powList.length - 1;
while(n > 0){
while(powList[ind] > n) ind--;
n -= powList[ind];
powers.unshift(ind);
}
- 2、计算乘积
我们初中的时候都学过幂运算,这里只需要用到一个简单的运算法则:
指数相乘运算公式:am·an=a^(m+n)。指数是幂运算a?(a≠0)中的一个参数,a为底数,n为指数,指数位于底数的右上角,幂运算表示指数个底数相乘。当n是一个正整数,a?表示n个a连乘。当n=0时,a?=1。
幂运算是一种关于幂的数学运算。同底数幂相乘,底数不变,指数相加。同底数幂相除,底数不变,指数相减。幂的乘方,底数不变,指数相乘。
所以我们只需要计算指数和再求幂即可。
for(let i = 0; i < queries.length; i++){
let ind = 0;
for(let j = queries[i][0]; j <= queries[i][1]; j++) ind += powers[j];
res.push(quickPow(2,ind));
}
完整AC代码如下:
AC代码
/**
* @param {number} n
* @param {number[][]} queries
* @return {number[]}
*/
var productQueries = function(n, queries) {
const res = [];
const powers = [];
const powList = [];
let num = 1;
const mod = BigInt(1000000007);
const quickPow = function(a, b) {
a = BigInt(a);
b = BigInt(b);
let ret = BigInt(1);
a = a % mod;
while (b) {
if (b & BigInt(1)) ret = ret * a % mod;
a = a * a % mod;
b = b >> BigInt(1);
}
return ret;
};
while(num <= n){
powList.push(num);
num *= 2;
}
let ind = powList.length - 1;
while(n > 0){
while(powList[ind] > n) ind--;
n -= powList[ind];
powers.unshift(ind);
}
for(let i = 0; i < queries.length; i++){
let ind = 0;
for(let j = queries[i][0]; j <= queries[i][1]; j++) ind += powers[j];
res.push(quickPow(2,ind));
}
return res;
};
公众号
关注公众号『前端也能这么有趣
』,获取更多有趣内容。
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!