格——LeetCode 第 163 場雙周賽 T1 的正方形覆蓋數(shù)學(xué)推導(dǎo)與 O(1) 實(shí)現(xiàn))
科學(xué)計(jì)算【免費(fèi)下載鏈接】codeforces-go算法競賽模板庫 by 靈茶山艾府 項(xiàng)目地址https://gitcode.com/GitHub_Trending/co/codeforces-go點(diǎn)擊查看免費(fèi)下載導(dǎo)讀本文基于本倉庫算法競賽模板庫 codeforces-go作者靈茶山艾府中 LeetCode 第 163 場雙周賽第一題題解深入剖析「覆蓋網(wǎng)格所需的最少傳感器數(shù)」這一經(jīng)典網(wǎng)格覆蓋問題。文章完整繼承原題解的數(shù)學(xué)推導(dǎo)、五種語言實(shí)現(xiàn)與復(fù)雜度分析并結(jié)合倉庫中的 Go 實(shí)現(xiàn)、自動(dòng)化測試 與 測試數(shù)據(jù) 進(jìn)行源碼級(jí)印證。讀完本文你將掌握「上取整 → 下取整」的整數(shù)除法等價(jià)變換技巧以及一類「固定邊長正方形鋪滿網(wǎng)格」問題的最小覆蓋計(jì)數(shù)通式并能在本倉庫中直接運(yùn)行測試驗(yàn)證結(jié)論。題目原型把「傳感器覆蓋范圍」翻譯成正方形覆蓋問題原題名為Minimum Sensors to Cover Grid覆蓋網(wǎng)格的最少傳感器數(shù)題目信息記錄在 a_test.go 的注釋中。題意可概括為有一個(gè) $n\times m$ 的網(wǎng)格每個(gè)傳感器可以覆蓋以自身為中心的一個(gè)正方形區(qū)域從中心往左最多走 $k$ 步往右最多走 $k$ 步往上、往下同理。問至少需要多少個(gè)傳感器才能覆蓋整個(gè) $n\times m$ 網(wǎng)格。本題解題的第一步也是最關(guān)鍵的一步是把「覆蓋范圍」這個(gè)幾何對象翻譯成一個(gè)確定的正方形從中心往左最多走 $k$ 步往右最多走 $k$ 步因此正方形邊長為 $k 1 k 2k1$。于是原問題被等價(jià)改寫為用 $(2k1)\times(2k1)$ 的正方形覆蓋 $n\times m$ 的網(wǎng)格最少要用多少個(gè)正方形。這一「問題等價(jià)轉(zhuǎn)化」正是整個(gè) O(1) 解法的起點(diǎn)一旦覆蓋范圍被確定為邊長為 $2k1$ 的正方形問題就從「幾何擺放」降維成了「計(jì)數(shù)分段」。核心推導(dǎo)最少個(gè)數(shù) 兩個(gè)方向上取整的乘積由于正方形的兩個(gè)維度相互獨(dú)立網(wǎng)格覆蓋可以被分解為按行分段與按列分段兩個(gè)一維問題按行分段每 $2k1$ 行分成一段$n$ 行一共要分成 $\left\lceil\dfrac{n}{2k1}\right\rceil$ 段按列分段每一段內(nèi)$m$ 列每 $2k1$ 列放一個(gè)正方形即每段需要 $\left\lceil\dfrac{m}{2k1}\right\rceil$ 個(gè)正方形。兩個(gè)方向上的段數(shù)相乘即為最少傳感器總數(shù)$$ \left\lceil\dfrac{n}{2k1}\right\rceil\cdot \left\lceil\dfrac{m}{2k1}\right\rceil $$邊界情況的自然性如果正方形比 $n\times m$ 的網(wǎng)格還大即 $2k1 n$ 且 $2k1 m$兩個(gè)上取整都會(huì)變成 $1$上式算出的結(jié)果是 $1$恰好符合只需要放一個(gè)傳感器即可覆蓋全網(wǎng)格的實(shí)際情形公式無需特判。上取整轉(zhuǎn)下取整一行代碼的落地技巧數(shù)學(xué)公式里的上取整 $\left\lceil\dfrac{a}\right\rceil$ 在計(jì)算機(jī)中并不能直接用整數(shù)除法得到。原題解給出的做法是借助上取整與下取整的轉(zhuǎn)換恒等式對正整數(shù) $a, b$ 有$$ \left\lceil\dfrac{a}\right\rceil \left\lfloor\dfrac{a-1}\right\rfloor 1 $$其中 $\left\lfloor\cdots\right\rfloor$ 正是整數(shù)除法向下取整。轉(zhuǎn)換后計(jì)算機(jī)只需要做一次普通的整數(shù)除法加一次加法// ceil(a/b) 的整數(shù)實(shí)現(xiàn) ((n - 1) / size 1)這個(gè)恒等式的直覺是$a$ 恰好被 $b$ 整除時(shí)$\lceil a/b\rceil a/b$而 $(a-1)/b a/b - 1$再加 $1$ 還原當(dāng) $a$ 不能被 $b$ 整除時(shí)$(a-1)/b$ 正好等于 $a/b$ 的整數(shù)商余數(shù)被消去再加 $1$ 即得上取整結(jié)果。它避免了浮點(diǎn)運(yùn)算也規(guī)避了浮點(diǎn)精度誤差是競賽代碼中處理向上取整的標(biāo)準(zhǔn)手法。五種語言的完整實(shí)現(xiàn)原題解給出了 Python3、Java、C、Go 四種語言的完整實(shí)現(xiàn)代碼與推導(dǎo)一一對應(yīng)此處完整繼承并補(bǔ)充注釋class Solution: def minSensors(self, n: int, m: int, k: int) - int: size k * 2 1 # 傳感器覆蓋正方形的邊長 # ceil(n/size) * ceil(m/size) 的上取整轉(zhuǎn)下取整寫法 return ((n - 1) // size 1) * ((m - 1) // size 1)class Solution { public int minSensors(int n, int m, int k) { int size k * 2 1; // 傳感器覆蓋正方形的邊長 return ((n - 1) / size 1) * ((m - 1) / size 1); } }class Solution { public: int minSensors(int n, int m, int k) { int size k * 2 1; // 傳感器覆蓋正方形的邊長 return ((n - 1) / size 1) * ((m - 1) / size 1); } };func minSensors(n, m, k int) int { size : k*2 1 // 傳感器覆蓋正方形的邊長 return ((n-1)/size 1) * ((m-1)/size 1) }值得說明的是Go 版代碼與倉庫中的 a.go逐字一致該文件正是本題在倉庫內(nèi)的標(biāo)準(zhǔn)提交實(shí)現(xiàn)可直接作為比賽模板使用。復(fù)雜度與邊界情況時(shí)間復(fù)雜度$\mathcal{O}(1)$——只做常數(shù)次四則運(yùn)算與網(wǎng)格大小無關(guān)空間復(fù)雜度$\mathcal{O}(1)$——只使用常數(shù)個(gè)變量。幾個(gè)值得注意的邊界情況$k 0$此時(shí) $size 1$答案退化為 $n \times m$即每個(gè)傳感器只覆蓋一個(gè)格子代碼無需特判即可正確處理正方形大于網(wǎng)格$2k1 n$ 或 $2k1 m$ 時(shí)對應(yīng)方向的上取整為 $1$公式自動(dòng)給出最小解 $1$數(shù)據(jù)范圍與溢出若 $n, m$ 取值較大建議使用 64 位整數(shù)類型如 Go 的int64、Java 的long來承接乘法結(jié)果避免中間乘積溢出原題解與倉庫實(shí)現(xiàn)均未依賴具體數(shù)據(jù)范圍此條為通用的工程建議。倉庫源碼佐證實(shí)現(xiàn)與測試閉環(huán)本倉庫為這道題提供了完整的實(shí)現(xiàn) 測試數(shù)據(jù) 自動(dòng)化測試閉環(huán)可以在本地直接復(fù)現(xiàn)題解結(jié)論。1. 核心實(shí)現(xiàn)a.go 只有 7 行包含函數(shù)簽名、邊長計(jì)算與一行返回值注釋中標(biāo)注了作者 B 站空間遵循倉庫統(tǒng)一的提交代碼風(fēng)格。2. 測試數(shù)據(jù)a.txt 以純文本方式保存了兩組用例每組 4 行3 個(gè)輸入?yún)?shù) 1 個(gè)期望輸出輸入 (n, m, k)size 2k1公式計(jì)算結(jié)果期望輸出5, 5, 13?5/3?·?5/3? 2·242, 2, 25?2/5?·?2/5? 1·11第二組用例恰好驗(yàn)證了上文的邊界結(jié)論當(dāng)正方形5×5比網(wǎng)格2×2還大時(shí)答案是 1。3. 自動(dòng)化測試a_test.go 通過testutil.RunLeetCodeFuncWithFile(t, minSensors, a.txt, 0)驅(qū)動(dòng)測試其底層實(shí)現(xiàn)在 leetcode/testutil/leetcode.go先讀取數(shù)據(jù)文件并用trimSpaceAndEmptyLine見 leetcode/testutil/helper.go去除空行與首尾空格通過反射獲取目標(biāo)函數(shù)minSensors的輸入?yún)?shù)個(gè)數(shù)NumIn與返回值個(gè)數(shù)NumOut按每fNumIn fNumOut行切分為一組完整用例——這就是a.txt中每組恰好 4 行的原因?qū)γ拷M用例調(diào)用目標(biāo)函數(shù)并用斷言框架比對實(shí)際輸出與期望輸出同時(shí)內(nèi)置超時(shí)檢測isTLE可在答案正確的前提下額外暴露超時(shí)風(fēng)險(xiǎn)。這一題解文件 提交代碼 數(shù)據(jù)文件 反射驅(qū)動(dòng)測試的組織方式是倉庫 leetcode 目錄下所有題目通用的標(biāo)準(zhǔn)工作流測試文件頭部注釋Generated by copypasta/template/leetcode/generator_test.go也表明它由倉庫自帶的模板生成器自動(dòng)產(chǎn)出。4. 本地運(yùn)行驗(yàn)證倉庫 go.mod 聲明 Go 版本為 1.23在倉庫根目錄執(zhí)行以下命令即可運(yùn)行本題全部用例go test ./leetcode/biweekly/163/a/ -v思路推廣一類「固定邊長鋪滿網(wǎng)格」問題的通用模板本題的核心結(jié)論可以推廣為一類問題的通用模板當(dāng)覆蓋物是軸對齊的正方形或矩形且兩個(gè)方向互相獨(dú)立時(shí)最少覆蓋個(gè)數(shù) 行方向上取整段數(shù) × 列方向上取整段數(shù)。這類問題在網(wǎng)格圖與幾何覆蓋類題目中反復(fù)出現(xiàn)做題時(shí)只需兩步確定覆蓋物在單個(gè)方向上的跨度本題為 $2k1$源自左右各 $k$ 步加自身一格用 $\left\lceil\dfrac{\text{方向總長}}{\text{跨度}}\right\rceil$ 計(jì)算該方向的段數(shù)最后相乘并用 $(x-1)/\text{跨度}1$ 的整數(shù)寫法落地。更系統(tǒng)的刷題路徑可參考原題解末尾的分類題單滑動(dòng)窗口、二分、單調(diào)棧、網(wǎng)格圖、動(dòng)態(tài)規(guī)劃等主題均收錄于 leetcode/SOLUTIONS.md 與倉庫各題解目錄本題所屬的網(wǎng)格覆蓋類題型本質(zhì)上考察的是問題等價(jià)轉(zhuǎn)化 整數(shù)上取整公式這兩項(xiàng)基本功。贊分享科學(xué)計(jì)算【免費(fèi)下載鏈接】codeforces-go算法競賽模板庫 by 靈茶山艾府 項(xiàng)目地址https://gitcode.com/GitHub_Trending/co/codeforces-go點(diǎn)擊查看免費(fèi)下載相關(guān)推薦codeforces-go 題解精講LeetCode 第 118 場雙周賽 B 題「最大化網(wǎng)格正方形洞的面積」—— 貪心與最長連續(xù)序列codeforces go 題解精講LeetCode 第 118 場雙周賽 B 題「最大化網(wǎng)格正方形洞的面積」—— 貪心與最長連續(xù)序列 本篇技術(shù)指南以 cod科學(xué)計(jì)算用最小矩形覆蓋點(diǎn)LeetCode 雙周賽 128 貪心解法多語言實(shí)現(xiàn)與 codeforces-go 源碼剖析用最小矩形覆蓋點(diǎn)LeetCode 雙周賽 128 貪心解法多語言實(shí)現(xiàn)與 codeforces go 源碼剖析 導(dǎo)讀 本文圍繞 LeetCode 第 128 場科學(xué)計(jì)算codeforces-go 題解深讀LeetCode 雙周賽 141 Q2「構(gòu)造最小位運(yùn)算數(shù)組 II」的 O(1) 位運(yùn)算推導(dǎo)與 Go 實(shí)現(xiàn)codeforces go 題解深讀LeetCode 雙周賽 141 Q2「構(gòu)造最小位運(yùn)算數(shù)組 II」的 O 1 位運(yùn)算推導(dǎo)與 Go 實(shí)現(xiàn) 本篇技術(shù)指南以 l科學(xué)計(jì)算上一篇AMD Ryzen SMUDebugTool5分鐘解鎖CPU隱藏性能的終極指南下一篇Ryzen處理器深度調(diào)校終極指南使用SMUDebugTool解鎖隱藏性能創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考