兩種方式處理已經訪問過的節點:一種是用visited存儲已經訪問過的1;另外一種是經過改變原始數值的值,好比將1改爲-1,這樣小於等於0的都會中止。html
Number of Islands 用了第一種方式,Number of Distinct Islands用了第二種方式數組
注意:若是採用更改原數組的方式,必定要注意加引用!!!函數
Number of Islands變種,假設給的矩陣四周都是陸地,和陸地相連不算island。優化
方法:與Number of Islands的search函數是同樣的,只是須要進行預處理 ,即先把與四周的1相連的全變成0,而後再作與Number of Islands同樣的操做spa
200. Number of Islands .net
我的理解dfs、bfs的時間複雜度都是 o(m*n)code
時間複雜度o(m*n)htm
1.這種寫法要改變原始輸入數組的值blog
錯誤版本:遞歸
條件判斷順序寫錯:grid[x][y] == '0' || x < 0 || x >= length || y < 0 || y >= width
這種寫法要報數組越界的錯誤,由於grid[x][y]會先訪問,實際上x、y這個時候可能就越界了,grid[x][y]必須放在這幾個越界判斷的後面
class Solution { public: int numIslands(vector<vector<char>>& grid) { int length = grid.size(); if(length <= 0) return 0; int width = grid[0].size(); int count = 0; for(int i = 0;i < length;i++){ for(int j = 0;j < width;j++){ if(grid[i][j] == '1'){ search(grid,i,j,length,width); count++; } } } return count; } void search(vector<vector<char>>& grid,int x,int y,int length,int width){ if(x < 0 || x >= length || y < 0 || y >= width || grid[x][y] == '0') return; grid[x][y] = '0'; search(grid,x-1,y,length,width); search(grid,x+1,y,length,width); search(grid,x,y-1,length,width); search(grid,x,y+1,length,width); } };
總體思路,從第一點開始找1,若是找到1,把全部的與這個1相連的1置爲0,由於這些1與這個1屬於同一個島嶼,用dfs去找把全部的1找到
https://blog.csdn.net/xudli/article/details/45912547
2.不改變原始輸入的值,仍是用dfs
class Solution { public: int numIslands(vector<vector<char>>& grid) { int width = grid.size(); if(width <= 0) return 0; int length = grid[0].size(); if(length <= 0) return 0; int count = 0; vector<vector<bool>> visited(width,vector<bool>(length,false)); for(int i = 0;i < width;i++){ for(int j = 0;j < length;j++){ if(grid[i][j] == '1' && visited[i][j] == false){ search(grid,i,j,visited); count++; } } } return count; } void search(vector<vector<char>> grid,int x,int y,vector<vector<bool>>& visited){ if(x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size() || grid[x][y] == '0' || visited[x][y] == true) return; visited[x][y] = true; search(grid,x-1,y,visited); search(grid,x+1,y,visited); search(grid,x,y-1,visited); search(grid,x,y+1,visited); } };
http://www.cnblogs.com/grandyang/p/4402656.html
bfs的兩種方法:
方法一:
class Solution { public: int numIslands(vector<vector<char>>& grid) { int m = grid.size(); if(m <= 0) return 0; int n = grid[0].size(); if(n <= 0) return 0; queue<pair<int,int>> q; int res = 0; for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if(grid[i][j] == '1'){ q.push(make_pair(i,j)); res++; grid[i][j] = '0'; while(!q.empty()){ int x= q.front().first; int y = q.front().second; q.pop(); //grid[x][y] = '0'; for(auto dir : dirs){ int x_cur = x + dir[0]; int y_cur = y + dir[1]; if(x_cur < 0 || x_cur >= m || y_cur < 0 || y_cur >= n || grid[x_cur][y_cur] == '0') continue; q.push(make_pair(x_cur,y_cur)); grid[x_cur][y_cur] = '0'; } } } } } return res; } vector<vector<int>> dirs{{-1,0},{1,0},{0,-1},{0,1}}; };
方法二:
class Solution { public: int numIslands(vector<vector<char>>& grid) { int m = grid.size(); if(m <= 0) return 0; int n = grid[0].size(); if(n <= 0) return 0; vector<vector<bool>> visited(m,vector<bool>(n,false)); queue<pair<int,int>> q; int res = 0; for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if(grid[i][j] == '1' && visited[i][j] == false){ q.push(make_pair(i,j)); res++; visited[i][j] = true; while(!q.empty()){ int x = q.front().first; int y = q.front().second; q.pop(); for(auto dir : dirs){ int x_cur = x + dir[0]; int y_cur = y + dir[1]; if(x_cur < 0 || x_cur >= m || y_cur < 0 || y_cur >= n || grid[x_cur][y_cur] == '0' || visited[x_cur][y_cur] == true) continue; visited[x_cur][y_cur] = true; q.push(make_pair(x_cur,y_cur)); } } } } } return res; } vector<vector<int>> dirs{{-1,0},{1,0},{0,-1},{0,1}}; };
錯誤方法一:
class Solution { public: int numIslands(vector<vector<char>>& grid) { int m = grid.size(); if(m <= 0) return 0; int n = grid[0].size(); if(n <= 0) return 0; queue<pair<int,int>> q; int res = 0; for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if(grid[i][j] == '1'){ q.push(make_pair(i,j)); res++; while(!q.empty()){ int x= q.front().first; int y = q.front().second; q.pop(); grid[x][y] = '0'; for(auto dir : dirs){ int x_cur = x + dir[0]; int y_cur = y + dir[1]; if(x_cur < 0 || x_cur >= m || y_cur < 0 || y_cur >= n || grid[x_cur][y_cur] == '0') continue; q.push(make_pair(x_cur,y_cur)); } } } } } return res; } vector<vector<int>> dirs{{-1,0},{1,0},{0,-1},{0,1}}; };
這個錯誤的方法與方法一相似,可是這個方法會在大數組的時候報超時,這是由於每次進行將1變成0的操做都是在隊列彈出以後,這樣會致使許多重複計算。
以下圖,從右下角的1開始遍歷,會先遍歷到左下角和右上角,這種狀況沒問題,可是當左下角和右上角都要遍歷到左上角時,都會把左上角這個1加入隊列進行一次計算,可是正確寫法卻不用。由於正確寫法,在加入隊列的時候就已經置爲0了,下一次再訪問到這個位置確定不會再加入隊列了。
694 Number of Distinct Islands
存儲搜索到的每一個島的形狀,利用set來保證存儲的形狀不同。形狀的存儲是根據每一個遍歷節點到每一個島的左上點的x、y差值,因此用pair的形式。由於每一個島有多個點,因此用vector存儲
用unordered_set編譯會報錯
class Solution { public: int numberofDistinctIslands(vector<vector<int>> &grid) { int m = grid.size(); if(m <= 0) return 0; int n = grid[0].size(); if(n <= 0) return 0; set<vector<pair<int,int>>> shapes; for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if(grid[i][j] == 1){ vector<pair<int,int>> shape; numberofDistinctIslands(grid,i,j,i,j,shape); shapes.insert(shape); } } } return shapes.size(); } void numberofDistinctIslands(vector<vector<int>>& grid,int x0,int y0,int i,int j,vector<pair<int,int>>& shape){ if(i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size() || grid[i][j] <= 0) return; grid[i][j] = -1; shape.push_back({x0 - i ,y0 - j}); numberofDistinctIslands(grid,x0,y0,i - 1,j,shape); numberofDistinctIslands(grid,x0,y0,i + 1,j,shape); numberofDistinctIslands(grid,x0,y0,i,j - 1,shape); numberofDistinctIslands(grid,x0,y0,i,j + 1,shape); } };
695. Max Area of Island
本身寫的
記錄每一個島嶼的節點個數就行了。每次大的循環是一個島嶼,每次遞歸是一個節點,因此在每次遞歸的時候++就行了,而後比較全部島嶼中最大的
class Solution { public: int maxAreaOfIsland(vector<vector<int>>& grid) { int m = grid.size(); if(m <= 0) return 0; int n = grid[0].size(); if(n <= 0) return 0; int max_num = 0; for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if(grid[i][j] == 1){ int num = 0; maxAreaOfIsland(grid,i,j,num); if(num > max_num) max_num = num; } } } return max_num; } void maxAreaOfIsland(vector<vector<int>>& grid,int i,int j,int& num){ if(i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size() || grid[i][j] <= 0) return; grid[i][j] = -1; num++; maxAreaOfIsland(grid,i - 1,j,num); maxAreaOfIsland(grid,i + 1,j,num); maxAreaOfIsland(grid,i,j - 1,num); maxAreaOfIsland(grid,i,j + 1,num); } };
130. Surrounded Regions
在4條邊上的O確定不會被包圍。
在4條邊上找O,而後尋找這個O的島嶼,而後把這4條邊能生成的島嶼全變成$,最後再將O變成X,$變成O。
這裏第一個代碼換了一種迭代的寫法,每次判斷的依據是如下一個節點爲依據,後一個代碼是本身常用的迭代寫法,都是能夠的。
class Solution { public: void solve(vector<vector<char> >& board) { int m = board.size(); if(m <= 0) return; int n = board[0].size(); if(n <= 0) return; for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if((i == 0 || i == board.size() -1 || j == 0 || j == board[0].size() - 1) && board[i][j] == 'O') solve(board,i,j); } } for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if(board[i][j] == 'O') board[i][j] = 'X'; if(board[i][j] == '$') board[i][j] = 'O'; } } return; } void solve(vector<vector<char> >& board,int i,int j){ board[i][j] = '$'; if(i >= 1 && board[i-1][j] == 'O') solve(board,i - 1,j); if(i < board.size() - 1 && board[i+1][j] == 'O') solve(board,i + 1,j); if(j >= 1 && board[i][j-1] == 'O') solve(board,i,j - 1); if(j < board[0].size() - 1 && board[i][j+1] == 'O') solve(board,i,j + 1); return; } };
本身最常寫的。
class Solution { public: void solve(vector<vector<char> >& board) { int m = board.size(); if(m <= 0) return; int n = board[0].size(); if(n <= 0) return; for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if((i == 0 || i == board.size() -1 || j == 0 || j == board[0].size() - 1) && board[i][j] == 'O') solve(board,i,j); } } for(int i = 0;i < m;i++){ for(int j = 0;j < n;j++){ if(board[i][j] == 'O') board[i][j] = 'X'; if(board[i][j] == '$') board[i][j] = 'O'; } } return; } void solve(vector<vector<char> >& board,int i,int j){ if(i < 0 || i >= board.size() || j < 0 || j >= board[0].size() || board[i][j] != 'O') return; board[i][j] = '$'; solve(board,i - 1,j); solve(board,i + 1,j); solve(board,i,j - 1); solve(board,i,j + 1); } };
並查集:
是否是在一個集合裏面
指向本身的優化
hash-map就能夠解決
操做:1.查詢
非遞歸比遞歸好。每次遞歸調用,程序保存了上一次調用的結果
集合表明
2.合併
434. Number of Islands II(lintcode)
https://www.cnblogs.com/grandyang/p/5190419.html
n表明行數、m表明列數,x是在行上的位置,y是在列上的位置,因此在roots中的座標應該是:m * x + y
roots表示全部節點所屬於的根,即屬於哪個集合,初始爲-1表示沒有屬於任何一個集合。
count表示集合個數,若是自己是一個重來沒屬於任何結合的位置,遍歷到的時候就須要 count++。
核心思路:兩個相鄰的位置不屬於同一個集合,這代表須要更新集合。
class Solution { public: /** * @param n: An integer * @param m: An integer * @param operators: an array of point * @return: an integer array */ vector<int> numIslands2(int n, int m, vector<Point> &operators) { // write your code here vector<int> result; int count = 0; vector<vector<int>> dirs{{0, -1}, {-1, 0}, {0, 1}, {1, 0}}; vector<int> roots(m*n,-1); for(int i = 0;i < operators.size();i++){ int x = operators[i].x; int y = operators[i].y; int index = m * x + y; if(roots[index] == -1){ roots[index] = index; count++; } for(auto dir : dirs){ int dx = x + dir[0]; int dy = y + dir[1]; int cur_index = m * dx + dy; if(dx < 0 || dx >= n || dy < 0 || dy >= m || roots[cur_index] == -1) continue; int p = findroot(roots,cur_index),q = findroot(roots,index); if(p != q){ roots[p] = q; count--; } } result.push_back(count); } return result; } int findroot(vector<int> roots,int index){ int root = roots[index]; while(root != index){ index = root; root = roots[index]; } return root; } };
178. Graph Valid Tree
https://www.cnblogs.com/grandyang/p/5257919.html
這道題給了咱們一個無向圖,讓咱們來判斷其是否爲一棵樹,咱們知道若是是樹的話,全部的節點必須是鏈接的,也就是說必須是連通圖,並且不能有環,因此咱們的焦點就變成了驗證是不是連通圖和是否含有環。
這個題與Number of Islands II的查找操做有點不太同樣,Number of Islands II中根節點存儲的是本身的下標,這個題的根節點存儲的是-1,因此find函數不太同樣。
class Solution { public: /** * @param n: An integer * @param edges: a list of undirected edges * @return: true if it's a valid tree, or false */ bool validTree(int n, vector<vector<int>> &edges) { // write your code here vector<int> roots(n,-1); for(int i = 0;i < edges.size();i++){ int p = findRoot(roots,edges[i][0]); int q = findRoot(roots,edges[i][1]); if(p == q) return false; roots[p] = q; } return edges.size() == n-1; } int findRoot(vector<int> roots,int index){ while(roots[index] != -1) index = roots[index]; return index; } };