分類: LeetCode

  • LeetCode 解題紀錄  221. Maximal Square 圖片中最大的正方形

    LeetCode 解題紀錄 221. Maximal Square 圖片中最大的正方形

    繼 200. Number of Islands 後,又遇到一個影像處理的問題。

    這題要用動態規劃來解,菜雞如我第一時間沒想到動態規劃,

    但是後來也自己解出來了,紀錄一下我的解題心路歷程。

    題目簡介:

    給你一張尺寸為 m x n 像素且只包含(0,1)的圖片稱為 Matrix ,

    其中 1 代表有像素的區域,找出此張圖片中含有 1 的最大正方形區域面積。

    第一階段想法:循序檢測法

    把每個點都當作候選正方形的左上角,

    先求 Row 再驗證每個 Col 是否符合正方形區域預想?

    若有,就回傳正方形區域面積;
    若無,就回傳 0。

    假設圖片中有 N 個元素,這個想法的時間複雜度為:

    $$O(N^{2})$$

    但是我們會遇到一個特殊情況,當最大正方形在驗證失敗的候選正方形的的情況,

    像是:

    就很尷尬,其中 $$S_m$$ 不等於 6 的原因是本圖中最大正方形是交由 min(m, n) 決定,

    所以不用檢查到 $$S_m = 6$$ 可以降低計算時間。

    結果:Wrong Answer

    第二階段:動態規劃法

    所以我決定再不增加時間複雜度的情形下,由小到大、每個正方形都檢測。

    使用動態規劃,每一步驟又拆成兩小步:

    第一步:驗證對角線是否為 ‘1’ ?

    第二步:驗證相應 X, Y軸是否為 ‘1’ ?

    若有任一步檢測到 ‘0’ ,則回傳步數 S 的平方當作正方形面積。

    不過鑑於這個作法時間複雜度遇到 Worst Case (全為 ‘1’ 的圖片時)仍為 $$O(N^{2})$$

    結果:Time Limited Error

    第三階段:利用影像(數據)特性降低時間複雜度。

    問自己一個問題:最低滿足圖片中最大正方形的條件是什麼?


    答案是任何大於(長/2)*(寬/2)的正方形,

    因為本題目中不考慮重疊問題,所以用數學上來說:

    一圖片尺寸為 m*n ,若有任意正方形面積大於(m/2 + k)(n/2 + k),

    而 k 恆大於零的話,此正方形為圖片中最大的正方形就成立。

    而候選次大正方形面積必定為(m/2 – k)(n/2 – k),

    所以每個點出發後,

    檢測 (m*n/4) + m + n – 1 個像素就知道這個正方形是不是最大的了。

    結果:Accept

  • 費波納契數列的最佳計算複雜度 O(logn) 實現及推導(fibonacci sequence in cpp)

    因為最近在解 Leetcode 的 91. Decode Ways


    要用到 Fibonacci sequence 來解,就我所知上次解 70Climbing Stairs 的時候,
    用 recursive 求解 Fibonacci sequence 的時候會 TLE。
    (所以我就偷懶跑去用 Python3 解大數)


    這次再遇到應該是要進步了xDDD


    正文開始:

    Fibonacci sequence 會長這個樣子:



    根據基本定義,第 N 個 Fibonacci value 等於前兩個 Fibonacci value 相加,
    我們便可以得到公式:



    得到公式以後把它擴展成 轉移矩陣 M 的形式,
    因為我們把前兩項當作初始值,所以 轉移矩陣 M 的指數會減二:



    所以我們現在只要計算 M 的 (n-2) 次方就能得到第 N 個 Fibonacci value。
    (左上角的 M00 會等於 第N個 Fibonacci value

    此時的計算複雜度為:O(n)

    以第 45 個 value 值來比較,此方法已經比遞迴快很多了xD




    但是我還要教你一個威力加強版外掛:平方求冪
    (左岸又稱快速冪 or double-and-add


    我們在這裡要用平方求冪去優化轉移矩陣 M。


    平方求冪的想法是把任何高階指數都化為與指數二有關的指數和,
    屁話一堆直接看數學比較快:


    如果你說 n 是 odd 怎麼辦?
    啊不簡單?直接減一再乘回去R~:




    這樣的好處是能大大的減少計算量,數學意義上來說是二分搜尋法,
    以找 n = 16 舉例,

    沒有平方求冪的版本會很老實地計算十五次乘法,
    而有平方求冪外掛的版本會跳著算:



    像是圖中有幾個節點,就計算幾次,
    每次都是跟自己相乘,所以實際上只要算黃色螢光筆那條路徑,
    不必考慮其他條黑色路徑。

    由此可以 16 = 2^4,所以有 4 個節點,只需計算 4次。
    此時又可推導出 計算複雜度為:O(logn)
    (log 以 2 為底。)


    用 C++ 實現的程式碼我放在這裡


    有興趣的可以直接拿來用,不用再造車輪了xD

    感謝各位