力扣--统计全1子矩阵
生活随笔
收集整理的這篇文章主要介紹了
力扣--统计全1子矩阵
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
力扣–統計全1子矩陣
文章目錄
- 力扣--統計全1子矩陣
- 一、題目描述
- 二、分析
- 方法一:枚舉
- 三、代碼
- 枚舉方法的代碼
一、題目描述
二、分析
方法一:枚舉
- 首先很直觀的想法,我們可以枚舉矩陣中的每個位置 (i,j),統計以其作為右下角時,有多少個元素全部都是 1的子矩形,那么我們就能不重不漏地統計出滿足條件的子矩形個數。
- 那么枚舉以后,我們怎么統計滿足條件的子矩形個數呢?
- 既然是枚舉以 (i,j) 作為右下角的子矩形個數,那么我們可以直接暴力地枚舉左上角 (k,y),看其組成的矩形是否滿足條件,時間復雜度為 O(nm)。但這樣無疑會使得時間復雜度變得很高,我們需要另尋他路。
- 我們預處理row 數組,其中row[i][j] 代表矩陣中 (i,j) 向左延伸連續 1 的個數,容易得出遞推式:
-
有了row 數組以后,如果要統計以 (i,j) 為右下角滿足條件的子矩形,我們就可以枚舉子矩形的高,即第 k行,看當前高度有多少滿足條件的子矩形。
-
由于我們知道第 k 行到第 i 行「每一行第 j 列向左延伸連續 1 的個數」 row[k][j],row[k+1][j],?,row[i][j],因此我們可以知道第 k 行滿足條件的子矩形個數就是這些值的最小值,它代表了「第 k 行到第 ii 行子矩形的寬的最大值」,公式化來說,即:
-
因此我們倒序枚舉 k,用num 變量來記錄到當前行 i 的最小值,即能在O(n) 的時間內統計出以 (i,j)為右下角滿足條件的子矩形個數。
-
舉個例子吧,如下圖的矩陣,我們現在計算以點mat[3][2]為右下角所構成的矩陣中子矩陣全為1的子矩陣的個數。
- 首先是第四行,dp[3][2] = 3,所以最小長度為3,所以sum += 3,這里計算的矩陣是只有第四行元素構成的矩陣,如下所示:
- 向上遍歷,第三行時,dp[2][2] = 3,最小長度依然為3,sum += 3,這里計算的矩陣是第三、四行元素構成的矩陣,如下所示:
- 繼續向上遍歷,第二行時,dp[1][2] = 2,此時的最小長度變為2,sum += 2,這里計算的矩陣是第二、三、四行元素構成的矩陣,如下所示:
- 繼續向上遍歷,第一行時,dp[0][2] = 1,此時的最小長度變為1,sum += 1,這里計算的矩陣是第一、二、三、四行元素構成的矩陣,如下所示:
- 該點遍歷結束,繼續循環遍歷所有節點后返回sum即可
三、代碼
枚舉方法的代碼
class Solution { public:int numSubmat(vector<vector<int>>& mat) {if(mat.empty()){return 0;}int m = (int)mat.size();int n = (int)mat[0].size();//dp[i][j]代表以i,j坐標為右端點,向左延續連續1的個數。意思是在第i行,j為終點,從j//向左連續1的個數,注意是連續連續連續vector<vector<int>> dp(m,vector<int>(n));for(int i = 0;i < m;i++){for(int j = 0;j < n;j++){//處理邊界if(j == 0){dp[i][j] = mat[i][j];}//如果當前位置為1,就代表可以在左邊的基礎上進行+1else if(mat[i][j] == 1){dp[i][j] = dp[i][j - 1] + 1;}//如果當前位置為0,那么dp代表的是連續1的個數,中間斷了,直接賦值為0else {dp[i][j] = 0;}}}//保存最后的結果int sum = 0;//遍歷,每次求以i,j坐標為右下角for(int i = 0;i < m;i++){for(int j = 0;j < n;j++){//保存點i,j坐標處向左延續連續1的個數int num = dp[i][j];//向上枚舉每一行for(int k = i;k >= 0;k--){//一旦某一行為0,那么求min后都為0,代表沒有構成矩陣if(num == 0){break;}//更新結果num = min(num,dp[k][j]);sum += num;}}}return sum;} }; 超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的力扣--统计全1子矩阵的全部內容,希望文章能夠幫你解決所遇到的問題。