↓快轉到主要內容
  1. LeetCode/

LeetCode 473: Matchsticks to Square

·1 分鐘· ·
LeetCode Medium Array Dynamic-Programming Backtracking Bit-Manipulation
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: medium 第一次嘗試:2022-11-16

  • 提交紀錄:Time Limit Exceeded → Accepted ×2 → Runtime Error ×3 → Time Limit Exceeded → Accepted ×2

解題思路
#

放置型回溯(Backtracking 模板):每根火柴要放進四個邊之一,邊長是 total / 4。剪枝很重要:

  • 總和不能被 4 整除,或最長的火柴超過邊長,直接 False。
  • 由大到小排序:大的先放,越早發現放不下。
  • 放進某個邊會超過邊長就跳過。
  • 如果這個邊的目前長度跟前面某個已經試過的邊一樣,結果也會一樣,跳過。

我的嘗試
#

這題提交了 9 次:

  • 第一版是對的四邊回溯,但沒有記憶化也沒有剪掉相同的邊,TLE。
  • 加上 @cache 的版本先是變數名稱打錯(value、e5,NameError)。修好之後四個分支用 + 加起來,每條分支都要走完才能相加,又 TLE;剛好有一次沒超時就 AC 了(回傳的是整數,非 0 就被當成 True)。
  • 2022-11-27 重寫時改成 or 而且由大到小排序,才穩定通過。

正確解法
#

class Solution:
    def makesquare(self, matchsticks: List[int]) -> bool:
        total = sum(matchsticks)
        if total % 4:
            return False
        side = total // 4
        matchsticks.sort(reverse=True)
        if matchsticks[0] > side:
            return False
        sides = [0] * 4
        def dfs(i):
            if i == len(matchsticks):
                return True
            tried = set()
            for k in range(4):
                if sides[k] + matchsticks[i] > side or sides[k] in tried:
                    continue
                tried.add(sides[k])
                sides[k] += matchsticks[i]
                if dfs(i + 1):
                    return True
                sides[k] -= matchsticks[i]
            return False
        return dfs(0)

複雜度
#

時間最壞 O(4^n),靠剪枝通過;空間 O(n)。

要特別避免的錯誤
#

  • 四個邊的結果要用 or 合併並且提早回傳,用 + 會把每條分支都走完。
  • 由大到小排序,小的先放會在很深的地方才發現失敗。
  • 長度相同的邊只需要試一次。

面試口說整理
#

總和要能被 4 整除,邊長是總和的四分之一。我把火柴由大到小排序,回溯時把每根放進四個邊之一,會超過邊長就跳過,目前長度跟試過的邊一樣也跳過,因為結果相同。最壞指數時間,但剪枝之後很快。

相關文章

LeetCode 78: Subsets
·1 分鐘
LeetCode Medium Array Backtracking Bit-Manipulation
LeetCode 78 解題筆記:每個元素選或不選;迭代寫法是每加入一個數,就把現有的每個子集合複製一份並加上它
LeetCode 90: Subsets II
·1 分鐘
LeetCode Medium Array Backtracking Bit-Manipulation
LeetCode 90 解題筆記:先排序;遇到跟前一個相同的數,只延伸上一步新產生的那些子集合
LeetCode 313: Super Ugly Number
·1 分鐘
LeetCode Medium Array Math Dynamic-Programming
LeetCode 313 解題筆記:LC 264 的推廣,每個質數一個指針;用 heap 的話要避免同一個數被推進去很多次
LeetCode 396: Rotate Function
·1 分鐘
LeetCode Medium Array Math Dynamic-Programming
LeetCode 396 解題筆記:F(k) 和 F(k - 1) 只差一個公式:F(k) = F(k - 1) + sum - n × 被移到最前面的那個數
LeetCode 397: Integer Replacement
·1 分鐘
LeetCode Medium Dynamic-Programming Greedy Bit-Manipulation Memoization
LeetCode 397 解題筆記:偶數一定除以 2;奇數選 +1 或 -1,用記憶化遞迴;n 很大不能開 n 大小的陣列
LeetCode 435: Non-overlapping Intervals
·1 分鐘
LeetCode Medium Array Dynamic-Programming Greedy Sorting
LeetCode 435 解題筆記:最少刪幾個 = 總數減掉最多能保留幾個;按右端點排序,貪心保留結束最早的