每日一題:2的冪數組中查詢范圍內的乘積;快速冪算法

題目選自2438. 二的冪數組中查詢范圍內的乘積

還是一樣的,先講解思路,然后再說代碼。

題目有一定難度,所以我要爭取使所有人都能看懂,用的方法會用最常規的思想。關于語言,都是互通的,只要你懂了一門語言,可以做到盡量理解其他語言。

每一次頭腦風暴都是一次十足的成長,請有耐心,即使是小白,看完自有收獲。

這道題跟之前那道題目重新排序得到 2 的冪呼應起來了,沒有看過的可以先去看一下前面那道題。


題目

給你一個正整數?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]?都對?10^9?+ 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 。答案對 109 + 7 取余后結果相同,所以返回 [2] 。

題目解析

(題目意思很簡單,但是給這個題目做翻譯的人翻譯的很差勁,所以得重新譯一遍)

給你一個正整數?n,你需要找到一個數組?powers。這個數組包含若干個 2 的冪(比如 1, 2, 4, 8, 16...),它們加起來正好等于?n。并且,powers?數組要用最少數量的 2 的冪,同時數組里的數必須是從小到大排列的(非遞減)。題目保證這種找法是唯一的。

然后,你還得到一個二維數組?queries,里面每個元素是?[left, right]。對于每一個?[left, right],你需要計算?powers?數組中從?left下標到?right下標(包含兩端)的所有數字的乘積

最后,因為乘積可能會非常大,所以你計算出來的每個乘積都要對 10^9 + 7 取余。最后把所有查詢的結果放在一個數組里返回。

1.題目與“2的冪”關聯

這個正整數n是這個數組相加起來的結果,很容易想到每一個數都有它相對應的二進制數。

例如,數字 13。它的二進制是?1101

2.powers數組是由2的冪組成的

每一個數都有它相對應的唯一二進制數,我們只需要把在?n?的二進制表示中出現的那些 2^k?找出來,然后按從小到大的順序排列就行了

  • 比如?n = 15,二進制是?1111,表示?15 = 8+4+2+1 = 2^3 + 2^2 + 2^1 + 2^0,所以?powers = [1, 2, 4, 8]
  • 比如?n = 12,二進制是?1100,表示?12 = 2^3 + 2^2,所以?powers = [4, 8]

3.如何處理查詢?queries?

1.對于每個?[left, right],計算?powers[left] * powers[left+1] * ... * powers[right]?對 10^9 + 7取余。

我們可以寫一個循環,從?left?遍歷到?right,把每個?powers[j]?乘起來,每乘一次就取余。

# 偽代碼
product = 1
for j from left to right:product = (product * powers[j]) % MOD

2.如果?queries?很多,或者?right - left?的距離很大,上面的循環可能會有點慢。有沒有更快的辦法?

所以我們需要利用指數的性質:2^a * 2^b = 2^(a+b)

也就是說,我們可以把?powers?數組中的每個元素看成是?2?的某個次方,計算乘積時只需要把這些次方加起來,然后再計算?2?的這個總次方。比如?powers = [1, 2, 4, 8],其實是?[2^0, 2^1, 2^2, 2^3],查詢?[0, 2]?的乘積是?2^0 * 2^1 * 2^2 = 2^(0+1+2) = 2^3 = 8

這樣可以避免直接計算大數。

4.如何快速計算?2?的高次方并取模?

  • 我們需要計算?2^x mod (10^9 + 7),其中?x?可能很大。
  • 直接用?2^x?會溢出,所以需要用到快速冪算法
  • 快速冪的核心思想是把指數表示成二進制形式,每次只處理一位。(后面代碼解析會詳細說明語法)

完整代碼

class Solution(object):def productQueries(self, n, queries):""":type n: int:type queries: List[List[int]]:rtype: List[int]"""MOD = 10**9 + 7# 第一步:把 n 表示成 2 的冪的和,得到 powers 數組powers = []power = 0while n > 0:if n & 1:  # 如果 n 的最低位是 1powers.append(1 << power)  # 加入 2^powern >>= 1  # n 右移一位power += 1# 第二步:把 powers 數組中的每個元素表示成 2 的指數# 比如 powers = [1, 2, 4, 8] 表示成 exponents = [0, 1, 2, 3]exponents = []for p in powers:exp = 0while (1 << exp) != p:exp += 1exponents.append(exp)# 第三步:快速冪算法,計算 2^x mod MODdef quick_pow(base, exp, mod):if exp == 0:return 1result = 1base %= modwhile exp > 0:if exp & 1:  # 如果 exp 的最低位是 1result = (result * base) % modbase = (base * base) % modexp >>= 1return result# 第四步:處理每個查詢answers = []for left, right in queries:# 計算范圍內所有指數的和total_exp = sum(exponents[left:right + 1])# 用快速冪計算 2^total_exp mod MODresult = quick_pow(2, total_exp, MOD)answers.append(result)return answers

代碼解析

代碼結構

代碼分為四個主要部分:

  1. 把?n?表示成 2 的冪的和,得到?powers?數組。
  2. 把?powers?數組中的每個元素表示成 2 的指數,得到?exponents?數組。
  3. 實現快速冪算法,用于計算?2^x mod MOD
  4. 處理每個查詢,計算答案。

詳細解析

  1. 第一部分:得到?powers?數組

    powers = []
    power = 0
    while n > 0:if n & 1:  # 如果 n 的最低位是 1powers.append(1 << power)  # 加入 2^powern >>= 1  # n 右移一位power += 1
    • 這一部分的作用是把?n?表示成 2 的冪的和。
    • n & 1?是位運算,檢查?n?的最低位是否為 1。如果是 1,說明需要加入?2^power
    • 1 << power?是位運算,表示?2^power
    • n >>= 1?是位運算,把?n?右移一位,相當于除以 2。
    • 比如?n = 15,二進制是?1111,循環過程如下:
      • 第一輪:n = 1111,最低位是 1,加入?2^0 = 1n?右移變成?111
      • 第二輪:n = 111,最低位是 1,加入?2^1 = 2n?右移變成?11
      • 第三輪:n = 11,最低位是 1,加入?2^2 = 4n?右移變成?1
      • 第四輪:n = 1,最低位是 1,加入?2^3 = 8n?右移變成?0
      • 結束,得到?powers = [1, 2, 4, 8]
  2. 第二部分:得到?exponents?數組

    exponents = []
    for p in powers:exp = 0while (1 << exp) != p:exp += 1exponents.append(exp)
    • 這一部分的作用是把?powers?數組中的每個元素表示成 2 的指數。
    • 比如?powers = [1, 2, 4, 8],我們需要得到?exponents = [0, 1, 2, 3],因為?1 = 2^0, 2 = 2^1, 4 = 2^2, 8 = 2^3
    • 對于每個?p,我們用一個循環找到?exp,使得?2^exp == p
  3. 第三部分:快速冪算法

    def quick_pow(base, exp, mod):if exp == 0:return 1result = 1base %= modwhile exp > 0:if exp & 1:  # 如果 exp 的最低位是 1result = (result * base) % modbase = (base * base) % modexp >>= 1return result
    • 這一部分的作用是快速計算?base^exp mod mod
    • 直接計算?base^exp?可能會導致數字非常大(比如?2^100),所以我們用快速冪算法。
    • 快速冪的核心思想是把指數?exp?表示成二進制形式,每次只處理一位。
    • 比如要計算?2^10 mod 1000000007
      • 10?的二進制是?1010
      • 從低位到高位處理:
        • 第 0 位是 0,不用乘。
        • 第 1 位是 1,乘上?2^2
        • 第 2 位是 0,不用乘。
        • 第 3 位是 1,乘上?2^8
      • 每次處理時,base?都會平方(base = base * base),這樣可以快速得到高次方的值。
      • 每次乘法后都對?mod?取模,避免數字過大。
  4. 第四部分:處理查詢

    answers = []
    for left, right in queries:# 計算范圍內所有指數的和total_exp = sum(exponents[left:right + 1])# 用快速冪計算 2^total_exp mod MODresult = quick_pow(2, total_exp, MOD)answers.append(result)
    • 這一部分的作用是處理每個查詢。
    • 對于每個查詢?[left, right],我們需要計算?powers[left] * powers[left+1] * ... * powers[right]
    • 因為?powers?中的每個元素是?2?的某個次方,所以乘積可以表示成?2?的指數之和。
    • 比如?powers = [1, 2, 4, 8]exponents = [0, 1, 2, 3],查詢?[0, 2]
      • 取出?exponents[0:3] = [0, 1, 2]
      • 計算指數之和:0 + 1 + 2 = 3
      • 計算?2^3 mod 1000000007 = 8
      • 答案是 8。
    • 最后把所有答案存入?answers?數組。

時間復雜度

  1. 第一部分:得到?powers?數組

    • 我們用一個 while 循環處理?n,每次把?n?右移一位,直到?n?變成 0。
    • n?的二進制表示有?log n?位(因為 2 的多少次方可以表示 n)。
    • 所以這一部分的時間復雜度是?O(log n)
  2. 第二部分:得到?exponents?數組

    • 對于?powers?數組中的每個元素?p,我們用一個 while 循環找到對應的指數?exp
    • powers?數組的長度最多是?log n(因為?n?的二進制表示最多有?log n?位 1)。
    • 對于每個?p,找到?exp?的循環次數最多是?log p,而?p?最大是?n,所以最壞情況下是?O(log n)
    • 總的時間復雜度是?O(log n * log n),但實際上?p?的值是遞增的,平均復雜度更低。
  3. 第三部分:快速冪算法

    • 快速冪算法的時間復雜度是?O(log exp),因為我們把指數?exp?表示成二進制形式,每次處理一位。
    • 在我們的題目中,exp?是指數之和,最壞情況下可能是?O(log n)?級別的(因為?n?本身是 2 的冪的和)。
  4. 第四部分:處理查詢

    • 假設有?q?個查詢(q?是?queries?的長度)。
    • 對于每個查詢,我們需要計算范圍內指數的和,時間復雜度是?O(log n)(因為?powers?數組的長度最多是?log n)。
    • 然后用快速冪計算結果,時間復雜度是?O(log exp),其中?exp?最壞情況下是?O(log n)
    • 所以每個查詢的復雜度是?O(log n)
    • 總的時間復雜度是?O(q * log n)

總時間復雜度

把所有部分加起來:

  • 第一部分:O(log n)
  • 第二部分:O(log n * log n)(實際更低)。
  • 第四部分:O(q * log n)

總的時間復雜度是?O(log n * log n + q * log n)。通常我們取最高項,所以是?O(q * log n)(因為?q?通常比?log n?大得多)。

空間復雜度

  • powers?數組和?exponents?數組的長度最多是?O(log n)
  • answers?數組的長度是?O(q)
  • 所以總的空間復雜度是?O(log n + q)

歡迎點贊、關注、收藏

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/92976.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/92976.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/92976.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ceph數據副本機制詳解

Ceph 數據副本機制詳解 Ceph 的數據副本機制是其保證數據可靠性和高可用性的核心設計&#xff0c;主要通過多副本&#xff08;Replication&#xff09; 和 糾刪碼&#xff08;Erasure Coding&#xff0c;EC&#xff09; 兩種方式實現。以下是對 Ceph 數據副本機制的全面解析&am…

【八股】Mysql中小廠八股

MySQL 基礎 數據庫三大范式&#xff08;中&#xff09; 第一范式: 要求數據庫表的每一列都是不可分割的原子數據項 如詳細地址可以分割為省市區等. 第二范式: 非主鍵屬性必須完全依賴于主鍵, 不能部分依賴 第二范式要確保數據庫表中的每一列都和主鍵相關, 而不能只與主鍵的某一…

怎么使用python查看網頁源代碼

使用python查看網頁源代碼的方法&#xff1a;1、使用“import”命令導入requests包import requests2、使用該包的get()方法&#xff0c;將要查看的網頁鏈接傳遞進去&#xff0c;結果賦給變量xx requests.get(urlhttp://www.hao123.com)3、用“print (x.text)”語句把網頁的內容…

C# 多線程:并發編程的原理與實踐

深入探討 C# 多線程&#xff1a;并發編程的原理與實踐引言在現代應用開發中&#xff0c;性能和響應速度往往決定了用戶體驗的優劣。尤其在計算密集型或者IO密集型任務中&#xff0c;傳統的單線程模型可能無法有效利用多核CPU的優勢。因此&#xff0c;多線程技術成為了解決這些問…

react 常用組件庫

1. Ant Design&#xff08;螞蟻設計&#xff09;特點&#xff1a;國內最流行的企業級 UI 組件庫之一&#xff0c;基于「中后臺設計體系」&#xff0c;組件豐富&#xff08;表單、表格、彈窗、導航等&#xff09;、設計規范統一&#xff0c;支持主題定制和國際化。適用場景&…

Python 爬蟲獲取淘寶商品信息、價格及主圖的實戰指南

在電商數據分析、競品調研或商品信息采集等場景中&#xff0c;獲取淘寶商品的詳細信息&#xff08;如價格、主圖等&#xff09;是常見的需求。雖然淘寶開放平臺提供了官方的 API 接口&#xff0c;但使用這些接口需要一定的開發和配置工作。本文將通過 Python 爬蟲的方式&#x…

Ruby面向對象編程中類與方法的基礎學習例子解析

代碼示例&#xff1a; Ruby面向對象編程中類與方法的基礎學習詳細例子 1. 引言 在面向對象編程&#xff08;OOP&#xff09;中&#xff0c;類是定義對象結構和行為的藍圖。Ruby是一種純面向對象的編程語言&#xff0c;它將一切視為對象&#xff0c;包括基本數據類型。本文將…

[ Mybatis 多表關聯查詢 ] resultMap

目錄 一. resultMap 1. 使用場景: 2. 查詢映射: (1)單表查詢映射: (2)多表查詢映射: a. 在學生表里查專業 b. 在專業表里查學生 二. 其他注意事項 1. 插件下載 2. #{ } 和 ${ }的區別 一. resultMap 1. 使用場景: (1)當數據庫列名和java類中的屬性名不同時,可? r…

Rust 性能提升“最后一公里”:詳解 Profiling 瓶頸定位與優化|得物技術

一、Profiling&#xff1a;揭示性能瓶頸的“照妖鏡”在過去的一年里&#xff0c;我們團隊完成了一項壯舉&#xff1a;將近萬核的 Java 服務成功遷移到 Rust&#xff0c;并收獲了令人矚目的性能提升。我們的實踐經驗已在《RUST練習生如何在生產環境構建萬億流量》一文中與大家分…

STM32H5 的 PB14 引腳被意外拉低的問題解析 LAT1542

關鍵字&#xff1a;STM32H5&#xff0c; GPIO 1. 問題現象 客戶反饋&#xff0c;使用 STM32H523RET6 應用中配置了兩個 IO 口&#xff0c;PC9 為輸出模式&#xff0c;內部下拉&#xff1b;PB14 為輸入模式&#xff0c;內部上拉。在程序中將 PC9 引腳輸出高電平&#xff0c;結…

【辦公自動化】如何使用Python讓Word文檔處理自動化?

在日常辦公中&#xff0c;Word文檔是最常用的文本處理工具之一。通過Python自動化Word文檔操作&#xff0c;可以大幅提高工作效率&#xff0c;減少重復勞動&#xff0c;特別適合批量生成報告、合同、簡歷等標準化文檔。本文將介紹幾種常用的Python操作Word文檔的方法&#xff0…

順序表的總結及模擬實現

目錄 一.線性表 二.順序表 1.概念 2.結構 3.要實現的接口函數 三.模擬實現順序表 1.定義出順序表的基本結構 2.實現檢查擴容功能 3.實現尾插 4.實現尾刪 5.實現頭插和頭刪 6.查找 7.修改 8.遍歷 9.在指定位置插入和刪除 四.順序表的優缺點及思考 a.順序表的弊端 …

Vue3 vs Vue2:全面對比與面試寶典

文章目錄Vue3 vs Vue2&#xff1a;全面對比與面試寶典引言&#xff1a;Vue框架的進化之路一、核心架構對比二、響應式系統的革命Vue2的響應式&#xff1a;像老式監控攝像頭Vue3的響應式&#xff1a;像智能AI監控系統三、API風格的進化Vue2的Options API&#xff1a;像填表格Vue…

Java Web開發:Session與Cookie詳細入門指南

在Web開發中&#xff0c;狀態管理是核心需求之一。本文將深入講解Java中Session和Cookie的使用方法&#xff0c;幫助你掌握用戶狀態管理的核心技術。 一、Session與Cookie基礎概念 特性SessionCookie存儲位置服務器內存/持久化存儲客戶端瀏覽器安全性較高&#xff08;敏感數據…

HTTPS與CA證書:安全通信全解析

CA&#xff08;Certificate Authority&#xff09;&#xff1a;證書頒發機構&#xff0c;負責簽發和管理數字證書&#xff0c;驗證證書持有者的身份。HTTPS&#xff1a;基于 SSL/TLS 協議的 HTTP&#xff0c;通過證書實現客戶端與服務器的身份驗證和數據加密。HTTPSHTTPSSL/TLS…

AI生成代碼時代的商業模式重構:從“軟件即產品”到“價值即服務”

2025年,全球AI代碼生成市場規模突破63億元(數據來源:《中國AI代碼生成行業發展報告》),開發者效率提升40%以上,軟件開發成本下降30%。這一技術浪潮正在顛覆傳統軟件行業的商業邏輯——當代碼生成變得像文字編輯一樣簡單時,企業如何構建可持續的商業模式? 本文將從硬件…

C#特性與反射知識梳理

C#中的**特性&#xff08;Attributes&#xff09;和反射&#xff08;Reflection&#xff09;**是兩個非常重要的概念&#xff0c;它們通常用于代碼的元編程&#xff0c;允許你在運行時獲取類型信息并對其進行操作。下面對這兩個概念進行詳細梳理&#xff1a;一、C#中的特性&…

SQL 語法詳解

SQL 語法詳解 引言 SQL&#xff08;Structured Query Language&#xff09;是一種用于數據庫管理的標準語言&#xff0c;它允許用戶進行數據的查詢、更新、插入和刪除等操作。SQL語法是數據庫管理和編程的基礎&#xff0c;本篇文章將詳細介紹SQL的基本語法和常用操作&#xff0…

為什么 sim(3) 中的尺度 s 與旋轉 R 相乘,而不是平移 t?

文章目錄為什么 sim(3) 中的尺度 s 與旋轉 R 相乘&#xff0c;而不是平移 t&#xff1f;1?? sim(3) vs SE(3)&#xff1a;結構對比與核心差異2?? 為什么尺度 s 不乘在 t 上&#xff1f;&#x1f6ab; 數學破壞&#xff1a;&#x1f9ed; 幾何解釋&#xff1a;3?? t 是“相…

如何為你的 Docker 容器設置代理網絡

一文搞定!如何為你的 Docker 容器設置代理網絡(及一個最常見的“坑”) 你是否遇到過這樣的窘境:在你的服務器上,代理工具(比如 Clash, V2Ray)運行得好好的,瀏覽器也能科學上網,但一旦把應用放進 Docker 容器,它就瞬間“失聯”,無法訪問外部世界? 別擔心,這是每個…