一、概述
輸入一個二維數組,元素均爲0或1,0表示陸地,1表示海洋,返回孤島個數。孤島定義爲一連串的陸地,其上下左右均爲海洋。孤島不能與二維數組邊緣相連。
服務器搞得我心態爆炸。本來這題可以提交的——那樣我就1360/6058,而不是現在的1925/6058,前進600名呢。結果十一點五十開始連不上,氣得我差點把電腦砸了。
二、分析
這個題第一眼我看到的時候是懵逼的:
什麼叫孤島啊?怎麼判斷孤島啊?
然後發現了孤島的特徵:它是一坨連起來的0,周圍全是1,注意只要上下左右四面,不用八方。
然後繼續歸納,我挨着邊緣,但三面環水的算不算啊?不算。只有嚴格四面環水的纔算。
那麼問題清楚了一些:和邊緣挨着的叫陸地,陸地都不算。
我們可以先把陸地都找出來,再在其餘的地方找孤島。
怎麼找陸地呢?這是個問題。可以先在二維數組,我們叫它地圖吧,在地圖最外圈走一圈,把所有的0標記爲陸地,然後再去內部,和陸地相連的也是陸地。這樣做。
如何實現“和陸地相連的也是陸地”?用DFS。DFS從一塊陸地出發,之後只要遇到0,就標記爲陸地,遇到1就返回。這點很重要。我們稱一次DFS爲一次污染。
要污染多少次呢?我們繞着地圖最外面走一圈,碰到陸地,我們把它標記爲-1吧,就開始污染。走完了也就污染完了。
現在看地圖,其中有三種元素:-1:陸地;0:島嶼;1:海水。然後開始找島嶼。
找島嶼的方法和找陸地一樣:我們這次要遍歷一整張地圖,遇到島嶼就開始污染,將其標記爲t,每次污染完一個島嶼,t遞增1。什麼叫污染完島嶼呢?DFS完一次啊。當我們遍歷完整張地圖,那麼就將所有的島嶼標記爲t、t+1、t+2等等。
返回t即可。
這裏有一個技巧,我們將t賦值爲10,以和0,1,-1區分開。然後返回t-10即可。
代碼如下:
class Solution {
void DFS(vector<vector<int>>& g,int i,int j,int t)
{
if(i<g.size()&&j<g[0].size()&&g[i][j]==0)
{
g[i][j]=t;
DFS(g,i,j+1,t);
DFS(g,i+1,j,t);
DFS(g,i,j-1,t);
DFS(g,i-1,j,t);
}
}
void DFS1(vector<vector<int>>& g,int i,int j,int t)
{
if(i<g.size()&&j<g[0].size()&&g[i][j]<=0)
{
g[i][j]=t;
DFS(g,i,j+1,t);
DFS(g,i+1,j,t);
DFS(g,i,j-1,t);
DFS(g,i-1,j,t);
}
}
public:
int closedIsland(vector<vector<int>>& g) {
int res=10;
for(int i=0;i<g[0].size();i++)
{
if(g[0][i]==0)
g[0][i]=-1;
if(g[g.size()-1][i]==0)
g[g.size()-1][i]=-1;
}
for(int i=0;i<g.size();i++)
{
if(g[i][0]==0)
g[i][0]=-1;
if(g[i][g[0].size()-1]==0)
g[i][g[0].size()-1]=-1;
}//標記地圖周邊的陸地
for(int i=0;i<g.size();i++)
for(int j=0;j<g[0].size();j++)
{
if(g[i][j]==-1)
DFS1(g,i,j,-1);
}//污染所有陸地
for(int i=1;i<g.size()-1;i++)
{
for(int j=1;j<g[0].size()-1;j++)
{
if(g[i][j]==0)
{
DFS(g,i,j,res);
res++;//污染島嶼
}
}
}
return res-10;
}
};
三、總結
這種題目第一次做,主要是思維的轉換——能夠找到解已經很好了,不要去奢求時間複雜度多麼好。也學到了用DFS來尋找二維數組中被包圍的塊的方法。