LeetCode -- 1504. Count Submatrices With All Ones 計數全為1的子矩陣

更新於 發佈於 閱讀時間約 13 分鐘

Description

Given an m x n binary matrix matreturn the number of submatrices that have all ones.

給定一個 m x n 二進位矩陣 mat ,傳回全為 1 的子矩陣的數量。

Solution

I'm going to share three different approaches here. The first one, although logically correct, has a time complexity of O(k² × m × n) (k=the number of one), which leads to a Time Limit Exceeded. I'm sharing it purely for documentation purposes.

這邊我會分享三種方法。其中第一種,邏輯雖然正確,但因為時間複雜度為 O(k² × m × n) (k=1的數量),所以會 Time Limit Exceeded。分享出來單純是為了記錄。

Coordinate transformation (座標化)

concept:Every rectangle has a top-left and bottom-right corner, so we can extract the coordinates of all the 1s and then check whether the rectangle formed by any two points contains any 0s. However, it's important to note that we only check rectangles defined by the top-left and bottom-right points—otherwise, we risk counting duplicates.

概念:所有的矩形都有左上和右下,因此我們可以將所有 1 的座標取出來,接著檢查兩個點所圍矩形裡有沒有 0。不過需要注意,我們只檢查左上和右下點圍出來的矩形,不然會重複計算。

program

import numpy as np
class Solution:
def numSubmat(self, mat: List[List[int]]) -> int:
height = len(mat)
weight = len(mat[0])
one = []

for i in range(height):
for j in range(weight):
if mat[i][j] == 1:
one.append([i,j])
answer = len(one)

mat = np.array(mat)
for i in range(len(one)):
for j in range(i+1,len(one)):
if one[i][0] <= one[j][0] and one[i][1] <= one[j][1]:
if 0 not in mat[one[i][0]:one[j][0]+1, one[i][1]:one[j][1]+1]:
answer += 1

return answer

Enumeration (枚舉)

For a given row, if we add each element to the one before it, each value becomes the width of a potential rectangle. For example, the row 0111 would transform into 0123. At this point, by looking upward from the current row, we can identify rectangles of size X × Y—as illustrated in the diagram below.

對於一個 row,如果將每一元素加上前一個元素,那每個元素就會變成矩形的寬度。舉個例子,0111 會變成 0123。此時,如果我們往上找就可以得到 X x Y 的矩形。如下圖所示

raw-image

program:

class Solution:
def numSubmat(self, mat: List[List[int]]) -> int:
m, n = len(mat), len(mat[0])
res = 0
row = [[0] * n for _ in range(m)]
sum = 0
for i in range(m):
for j in range(n):
if j == 0:
row[i][j] = mat[i][j]
elif mat[i][j] == 0:
continue
else:
row[i][j] = row[i][j-1]+1 # +1:row[i][j]
cur = row[i][j]
for k in range(0,i+1):
if row[i-k][j] == 0:
break
cur = min(cur, row[i-k][j])
sum += cur
return sum

Monotonic stack (單調堆疊)

First, we initialize a list to store the heights, starting with [0] * len(mat[0]). The first thing we do is increment the value at each index where the current cell is 1. This way, we record the height of consecutive 1s ending at that index for the current row.

For example, given ([0,1,1], [1,1,0]), when we process the second row, the height list becomes [1,2,0].

首先,我們有一個存儲高度的串列,初始為 0 * len(mat[0])。因此,我們第一件要做的事是將為 1 的加一,以此紀錄目前該 row 該 index 為底的高度,ex:([0,1,1][1,1,0]) 當遍歷到第二層 row 時 -> ([1,2,0])。

Next, we use a stack that stores three pieces of information: index, count, and height. This stack is updated once per row, just like the height list is refreshed at the end of each row.

There's a key concept readers need to understand: although we store information for every element, we must perform a crucial step before pushing new data. If the current height is not greater than the top of the stack, we remove all previous entries with a height taller than the current one. This ensures that when we calculate the area of an X × Y rectangle, we can correctly include all valid submatrices.

If this explanation feels a bit abstract, you can refer to the formula in the code:

prev + (i - j) * h

Here:

  • prev is the count from the previous stack entry (equivalent to stack[j][1])
  • i is the current index
  • j is the index of the previous entry
  • h is the height of that entry

If it still feels unclear, the diagram below should help clarify the concept visually.

接著,我們有一個 stack。這個 stack 負責儲存三項資訊:index, count, height,並且每行會更新一次,就像高度串列每行結束後會全部更新完一樣。然後有個重要的概念讀者必須知道,雖然我們會將每個元素的資訊都儲存起來,但在存儲之前,我們要做一項非常重要的動作。當目前高度並非 stack 裡最高時,程式碼會去刪除前面比目前高度還要高的資訊,如此一來可以保證,當我們在計算 XxY 矩形時可以涵括到每一個。如果覺得這樣講有點抽象可以搭配程式碼中的這項公式 prev + (i - j) * h 來看。prev 是前一項的 count,也可以想成 stack[j][1];i 為當前 index;j 為前一項的 index;h 為該項的高度。如果還是覺得抽象,可以參考下方圖片。

raw-image

program:

class Solution:
def numSubmat(self, mat: List[List[int]]) -> int:
height = [0] * len(mat[0])
res = 0
for row in mat:
for i, x in enumerate(row):
height[i] = 0 if x==0 else height[i] + 1
stack = [[-1,0,-1]]
for i, h in enumerate(height):
while stack[-1][2] >= h:
stack.pop()
j, prev, _ = stack[-1]
cur = prev + (i-j)*h
stack.append([i,cur,h])
res += cur
return res
留言
avatar-img
留言分享你的想法!
avatar-img
周濡墨的沙龍
17會員
120內容數
有別於未付費的文章,專題區的文章偏向愛情短篇小說,較有戲劇性,篇幅也會較長;未付費文章會偏向極短篇小說,並且以類似散文的手法寫作
周濡墨的沙龍的其他內容
2025/08/19
Description You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of thei
Thumbnail
2025/08/19
Description You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of thei
Thumbnail
2025/08/19
前言 為了完成 LeetCode 題目 2. Add Two Numbers,我特地學習了 Python 中的 Linked List。不過我花了大約一小時的時間翻閱中英文影片及文章,卻始終找不到滿意的解說。 於是,我請 AI 當我的老師,生成了一篇 Python Linked List 教學。
2025/08/19
前言 為了完成 LeetCode 題目 2. Add Two Numbers,我特地學習了 Python 中的 Linked List。不過我花了大約一小時的時間翻閱中英文影片及文章,卻始終找不到滿意的解說。 於是,我請 AI 當我的老師,生成了一篇 Python Linked List 教學。
2025/08/15
Soup Servings - LeetCode Description You have two soups, A and B, each starting with n mL. On every turn, one of the following four serving operatio
2025/08/15
Soup Servings - LeetCode Description You have two soups, A and B, each starting with n mL. On every turn, one of the following four serving operatio
看更多
你可能也想看
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Subarray Sums Divisible by K 給定一個整數陣列,請計算有幾個區間和能夠整除k的連續區間? 測試範例 Input: nums = [4,5,0,-2,-3,1], k = 5 Output: 7
Thumbnail
題目敘述 Subarray Sums Divisible by K 給定一個整數陣列,請計算有幾個區間和能夠整除k的連續區間? 測試範例 Input: nums = [4,5,0,-2,-3,1], k = 5 Output: 7
Thumbnail
Continuous Subarray Sum 給定一個整數陣列,請問是否存在一段區間和能夠整除k的連續區間,而且區間長度≥2? 如果存在,返回True。 無果無解,返回False。 例如[2,5,3,1,8,6], k = 6, 其中[3,1,8]是區間和能夠整除6的連續區間,而且區間長度≥2
Thumbnail
Continuous Subarray Sum 給定一個整數陣列,請問是否存在一段區間和能夠整除k的連續區間,而且區間長度≥2? 如果存在,返回True。 無果無解,返回False。 例如[2,5,3,1,8,6], k = 6, 其中[3,1,8]是區間和能夠整除6的連續區間,而且區間長度≥2
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)。 我們必須從裡面選擇一個元素刪除之後,請問連續為1的最長子陣列的長度是多少? 測試範例 Example 1: Input: nums = [1,1,0,1] Output: 3 Explanation:
Thumbnail
題目敘述 題目會給定一個二元陣列nums(也就是說,陣列元素只有0,1這兩種情況)。 我們必須從裡面選擇一個元素刪除之後,請問連續為1的最長子陣列的長度是多少? 測試範例 Example 1: Input: nums = [1,1,0,1] Output: 3 Explanation:
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,我們每回合可以挑選總和為K的兩個數字,形成一個K-Sum pair。 請問我們最多可以製造幾個K-Sum pair? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,2,3,4], k = 5 Output
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,我們每回合可以挑選總和為K的兩個數字,形成一個K-Sum pair。 請問我們最多可以製造幾個K-Sum pair? 題目的原文敘述 測試範例 Example 1: Input: nums = [1,2,3,4], k = 5 Output
Thumbnail
題目敘述 題目會給兩個陣列nums1和nums2。 題目要求我們從中同步選擇長度為k的子序列,並且最大化子序列的分數, 回傳最高的分數值。 分數的定義: 分數 = (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] ,
Thumbnail
題目敘述 題目會給兩個陣列nums1和nums2。 題目要求我們從中同步選擇長度為k的子序列,並且最大化子序列的分數, 回傳最高的分數值。 分數的定義: 分數 = (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] ,
Thumbnail
題目敘述 題目會給我們一個參數k 和 目標值n。 請問我們從1~9內挑k個相異的數字,使得他們的總和為n 的組合數有多少? 挑選時,每個數字必須相異,而且每個數字只能選一次。 題目的原文敘述 測試範例 Example 1: Input: k = 3, n = 7 Output: [
Thumbnail
題目敘述 題目會給我們一個參數k 和 目標值n。 請問我們從1~9內挑k個相異的數字,使得他們的總和為n 的組合數有多少? 挑選時,每個數字必須相異,而且每個數字只能選一次。 題目的原文敘述 測試範例 Example 1: Input: k = 3, n = 7 Output: [
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,和一個指定的k值。 請問,在輸入陣列nums中,有幾個子陣列的元素總合恰好為k ? 例如: nums = [1,2,3], k = 3 則有兩個子陣列的元素總合為3,分別是[1,2] 和 [3] 如果是第一次聽到或接觸前綴和prefix的同學
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,和一個指定的k值。 請問,在輸入陣列nums中,有幾個子陣列的元素總合恰好為k ? 例如: nums = [1,2,3], k = 3 則有兩個子陣列的元素總合為3,分別是[1,2] 和 [3] 如果是第一次聽到或接觸前綴和prefix的同學
Thumbnail
題目敘述 題目的情境是設計並且實現一個包含所有正整數的數據流,以set集合的方式存在。 數據流 = {1, 2, 3, 4, ..., ∞} 要求我們去實現定義好的function介面: SmallestInfiniteSet()建構子,初始化這個包含所有正整數的數據流。 int po
Thumbnail
題目敘述 題目的情境是設計並且實現一個包含所有正整數的數據流,以set集合的方式存在。 數據流 = {1, 2, 3, 4, ..., ∞} 要求我們去實現定義好的function介面: SmallestInfiniteSet()建構子,初始化這個包含所有正整數的數據流。 int po
Thumbnail
題目會給我們一個方陣,要求我們計算兩條對角線的元素總和。
Thumbnail
題目會給我們一個方陣,要求我們計算兩條對角線的元素總和。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News