554. Brick Wall
MediumDescription
給定一面磚牆(2D 陣列表示每行磚塊的寬度),畫一條從頂到底的垂直線,使得穿過的磚塊數最少。如果線恰好在磚塊邊界上,不算穿過。回傳穿過的最少磚塊數。
Example:
Input: wall = [[1,2,2,1],[3,1,2],[1,3,2],[2,4],[3,1,2],[1,3,1,1]] Output: 2
Intuition#
核心思路:「穿過最少磚塊」等價於「經過最多邊界」。統計每個位置有多少邊界,取最大值,答案 = 行數 - 最多邊界數。
- 對每一行計算前綴和(不含最後一塊),前綴和代表邊界位置
- 用 HashMap 統計每個邊界位置出現幾次
- 出現最多次的邊界位置就是最佳畫線位置
Approaches#
1: Brute Force(每個位置都試)#
- 概念: 對每個可能的 x 位置,檢查每行是否有邊界
- 時間複雜度:
O(n * W)- n 為行數,W 為牆寬 - 空間複雜度:
O(n * W)- 儲存所有邊界
class Solution {
fun leastBricks(wall: List<List<Int>>): Int {
val width = wall[0].sum()
val borders = Array(wall.size) { HashSet<Int>() }
for (i in wall.indices) {
var sum = 0
for (j in 0 until wall[i].size - 1) {
sum += wall[i][j]
borders[i].add(sum)
}
}
var maxBorders = 0
for (x in 1 until width) {
var count = 0
for (i in wall.indices) {
if (x in borders[i]) count++
}
maxBorders = maxOf(maxBorders, count)
}
return wall.size - maxBorders
}
}⭐2: HashMap 統計邊界頻率#
- 概念: 對每行計算邊界位置(前綴和),用 HashMap 統計每個位置出現次數,取最大值
- 時間複雜度:
O(n * m)- n 為行數,m 為每行平均磚塊數 - 空間複雜度:
O(n * m)- HashMap
class Solution {
fun leastBricks(wall: List<List<Int>>): Int {
val borderCount = HashMap<Int, Int>()
for (row in wall) {
var sum = 0
for (i in 0 until row.size - 1) {
sum += row[i]
borderCount[sum] = (borderCount[sum] ?: 0) + 1
}
}
val maxBorders = borderCount.values.maxOrNull() ?: 0
return wall.size - maxBorders
}
}🔑 Takeaways#
- Pattern: 轉換問題——「最小化穿過」轉為「最大化對齊邊界」
- 關鍵技巧: 前綴和求邊界位置 + HashMap 計頻率;注意不要包含牆的最右邊界(因為所有行都在那裡結束)