并查集 leetcode 编程题
2017-09-26 20:17
351 查看
先看先人的总结:
[置顶] 并查集详解 (转)
傻子都能看懂的并查集入门
将所有元素的集合代表设置成自己,rank层级设置成0,
查找:
查找一个元素的集合代表,原理是指针循环操作
合并集合:
将两个集合的集合代表设置成一个。一般根据rank层级选择层级大的做代表。目的是使得树的分部尽量均匀
class Solution {
public:
void dfs(vector<vector<int>>& M,vector<int>& visited,int laoda)
{
for(int j=0;j<M.size();j++)
{
if(M[laoda][j]==1&&visited[j]==0)//当前节点还没有走访,而且是当前阵营
{
visited[j]=1;//设置成已走访
dfs(M,visited,j);//当前这个小鹏有的朋友全部走访
}
}
}
int findCircleNum(vector<vector<int>>& M) {
int n=M.size();//小朋友的数目
vector<int> visited(n,0);//初始化走访数组,0表示还没有走访到
int count=0;
for(int i=0;i<n;i++)
{
if(visited[i]==0)//还没有走访,说明这是一个新的朋友圈,因为深度优先遍历保证一个朋友圈的所有小朋友都一次性的走访一遍
{
count++;
dfs(M,visited,i);//深度优先遍历将这个新的朋友圈的小朋友全部走访一遍
}
}
return count;
}
};
上面方法的缺点是,每一层级都要重新从第一个小朋友开始判断,虽然已经走访过的孩子不需要在走访,但是当朋友圈很多时,还是很复杂。
public:
//查询操作
int find(int i, vector<int>& parent){
while(parent[i]!=i)//当没到根节点时
{
parent[i]=parent[parent[i]];//路径压缩,跨级提升。原来是县对市,现在县变成了地级市,直接找到省委,市直接找到
i=parent[i];
}
return i;//最后找到代表节点
}
//合并操作
void unionFriend(vector<int>& parent,vector<int>& rank,int& i,int& j)
{
int iFind=find(i,parent);//寻找根代表
int jFind=find(j,parent);
if(iFind==jFind) return ;
if(rank[iFind]>rank[jFind])
{
parent[jFind]=iFind;
}
else
{
parent[iFind]=jFind;
if(rank[iFind]==rank[jFind])
rank[jFind]++;
}
count--;
}
int findCircleNum(vector<vector<int>>& M) {
int n=M.size();
count=n;
//初始化过程
vector<int> parent(n,0);
vector<int> rank(n,0);//层级都设置成0
for(int i=0;i<n;i++)
{
parent[i]=i;//每个节点的根节点都设置成自己
}
for(int i=0;i<n-1;i++)
for(int j=i+1;j<n;j++)//这种遍历没有重复
{
if(M[i][j])//两个人是朋友
{
unionFriend(parent,rank,i,j);//把两个人合并起来
}
}
return count;
}
private:
int count=0;
};
(water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
Answer: 1
Example 2:
Answer: 3
方式与上题相同,设置访问数组,记录已经访问过的元素
class Solution {
public:
void dfs(vector<vector<int>>& visited,vector<vector<char>>& grid,int i,int j,int&row,int& col)
{
int oren[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
visited[i][j]=1;
for(int k=0;k<4;k++)
{
int curi=i+oren[k][0];
int curj=j+oren[k][1];
if(curi>=0&&curi<row&&curj>=0&&curj<col&&visited[curi][curj]==0&&grid[curi][curj]=='1')
dfs(visited,grid,curi,curj,row,col);
}
}
int numIslands(vector<vector<char>>& grid) {
int row=grid.size();
if(row==0) return 0;
int col=grid[0].size();
int count=0;
vector<vector<int>> visited(row,vector<int>(c
4000
ol,0));//访问数组
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(grid[i][j]=='1'&&visited[i][j]==0)
{
count++;
dfs(visited,grid,i,j,row,col);
}
}
}
return count;
}
};其他人的方法:省略visited数组,将原来的1改成0,节省空间。意义不是很大。
public class Solution {
private int n;
private int m;
public int numIslands(char[][] grid) {
int count = 0;
n = grid.length;
if (n == 0) return 0;
m = grid[0].length;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++)
if (grid[i][j] == '1') {
DFSMarking(grid, i, j);
++count;
}
}
return count;
}
private void DFSMarking(char[][] grid, int i, int j) {
if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') return;
grid[i][j] = '0';
DFSMarking(grid, i + 1, j);
DFSMarking(grid, i - 1, j);
DFSMarking(grid, i, j + 1);
DFSMarking(grid, i, j - 1);
}
[置顶] 并查集详解 (转)
傻子都能看懂的并查集入门
一、并查集简单总结
1、数据
parent 集合代表,rank集合层级,data 元素的数值2、三个操作
初始化:将所有元素的集合代表设置成自己,rank层级设置成0,
查找:
查找一个元素的集合代表,原理是指针循环操作
合并集合:
将两个集合的集合代表设置成一个。一般根据rank层级选择层级大的做代表。目的是使得树的分部尽量均匀
二、题目示例
547. Friend Circles
给定一个矩阵,由0和1组成,1代表横纵坐标的两个人是朋友,朋友关系具有传递性。求有多少个朋友集合。思路1:DFS
可以直接使用DFS。建立一个标记数组,已经遍历过的小孩不需要做操作。这样的时间复杂度并不高,因为每个小孩只走访一次。如果只有几个小朋友,那么dfs的递归调用只有几次。class Solution {
public:
void dfs(vector<vector<int>>& M,vector<int>& visited,int laoda)
{
for(int j=0;j<M.size();j++)
{
if(M[laoda][j]==1&&visited[j]==0)//当前节点还没有走访,而且是当前阵营
{
visited[j]=1;//设置成已走访
dfs(M,visited,j);//当前这个小鹏有的朋友全部走访
}
}
}
int findCircleNum(vector<vector<int>>& M) {
int n=M.size();//小朋友的数目
vector<int> visited(n,0);//初始化走访数组,0表示还没有走访到
int count=0;
for(int i=0;i<n;i++)
{
if(visited[i]==0)//还没有走访,说明这是一个新的朋友圈,因为深度优先遍历保证一个朋友圈的所有小朋友都一次性的走访一遍
{
count++;
dfs(M,visited,i);//深度优先遍历将这个新的朋友圈的小朋友全部走访一遍
}
}
return count;
}
};
上面方法的缺点是,每一层级都要重新从第一个小朋友开始判断,虽然已经走访过的孩子不需要在走访,但是当朋友圈很多时,还是很复杂。
思路2:采用并查集
class Solution {public:
//查询操作
int find(int i, vector<int>& parent){
while(parent[i]!=i)//当没到根节点时
{
parent[i]=parent[parent[i]];//路径压缩,跨级提升。原来是县对市,现在县变成了地级市,直接找到省委,市直接找到
i=parent[i];
}
return i;//最后找到代表节点
}
//合并操作
void unionFriend(vector<int>& parent,vector<int>& rank,int& i,int& j)
{
int iFind=find(i,parent);//寻找根代表
int jFind=find(j,parent);
if(iFind==jFind) return ;
if(rank[iFind]>rank[jFind])
{
parent[jFind]=iFind;
}
else
{
parent[iFind]=jFind;
if(rank[iFind]==rank[jFind])
rank[jFind]++;
}
count--;
}
int findCircleNum(vector<vector<int>>& M) {
int n=M.size();
count=n;
//初始化过程
vector<int> parent(n,0);
vector<int> rank(n,0);//层级都设置成0
for(int i=0;i<n;i++)
{
parent[i]=i;//每个节点的根节点都设置成自己
}
for(int i=0;i<n-1;i++)
for(int j=i+1;j<n;j++)//这种遍历没有重复
{
if(M[i][j])//两个人是朋友
{
unionFriend(parent,rank,i,j);//把两个人合并起来
}
}
return count;
}
private:
int count=0;
};
200. Number of Islands
Given a 2d grid map of'1's (land) and
'0's
(water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
11110 11010 11000 00000
Answer: 1
Example 2:
11000 11000 00100 00011
Answer: 3
思路1:DFS
方式与上题相同,设置访问数组,记录已经访问过的元素class Solution {
public:
void dfs(vector<vector<int>>& visited,vector<vector<char>>& grid,int i,int j,int&row,int& col)
{
int oren[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
visited[i][j]=1;
for(int k=0;k<4;k++)
{
int curi=i+oren[k][0];
int curj=j+oren[k][1];
if(curi>=0&&curi<row&&curj>=0&&curj<col&&visited[curi][curj]==0&&grid[curi][curj]=='1')
dfs(visited,grid,curi,curj,row,col);
}
}
int numIslands(vector<vector<char>>& grid) {
int row=grid.size();
if(row==0) return 0;
int col=grid[0].size();
int count=0;
vector<vector<int>> visited(row,vector<int>(c
4000
ol,0));//访问数组
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(grid[i][j]=='1'&&visited[i][j]==0)
{
count++;
dfs(visited,grid,i,j,row,col);
}
}
}
return count;
}
};其他人的方法:省略visited数组,将原来的1改成0,节省空间。意义不是很大。
public class Solution {
private int n;
private int m;
public int numIslands(char[][] grid) {
int count = 0;
n = grid.length;
if (n == 0) return 0;
m = grid[0].length;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++)
if (grid[i][j] == '1') {
DFSMarking(grid, i, j);
++count;
}
}
return count;
}
private void DFSMarking(char[][] grid, int i, int j) {
if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') return;
grid[i][j] = '0';
DFSMarking(grid, i + 1, j);
DFSMarking(grid, i - 1, j);
DFSMarking(grid, i, j + 1);
DFSMarking(grid, i, j - 1);
}
相关文章推荐
- 【动态规划】Leetcode编程题解:70. Climbing Stairs
- leetcode 174. Dungeon Game 完美世界秋招编程题2
- 乐视2017暑期实习生编程题 交换宝石(并查集)
- leetcode016-Accounts Merge(并查集应用)
- leetcode经典编程题(9)
- 【动态规划】Leetcode编程题解:303. Range Sum Query - Immutable Add to List
- 【动态规划】Leetcode编程题解:198. House Robber Add to List
- 【数组】Leetcode编程题解:495. Teemo Attacking
- leetcode经典编程题(10)
- 【动态规划】Leetcode编程题解:121. Best Time to Buy and Sell Stock Add to List
- [置顶] [编程题] LeetCode上的Dynamic Programming(动态规划)类型的题目
- 【动态规划】Leetcode编程题解:523. Continuous Subarray Sum Add to List
- 【动态规划】Leetcode编程题解:338. Counting B 4000 its
- LeetCode 200. Number of Islands (并查集)
- 初刷leetcode编程题总结
- leetcode编程题(2)Add Two Numbers
- Leetcode 200 Number of Islands 并查集
- LeetCode Union-Find(并查集) 专题(一)
- LeetCode 547 Friend Circles(并查集)
- leetcode编程题(3)Longest Substring Without Repeating Characters