1.省份数量(并查集)
题目描述:
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
难度:中等
数据范围:
- 1 <= n <= 200
- n == isConnected.length
- n == isConnected[i].length
- isConnected[i][j] 为 1 或 0
- isConnected[i][i] == 1
- isConnected[i][j] == isConnected[j][i]
题目地址
题解:
先放上临时写的并查集,距离上次写并查集已经有段时间了,代码不是很简洁,也没有打磨,但通过测试用例够用了。
class DJset{
int *parent;
int count;
public:
DJset(int n){
parent=new int[n];
for(int i=0;i<n;i++)
parent[i]=i;
count=n;
}
int Find(int m){
if(parent[m]==m)
return m;
else
return Find(parent[m]);
}
void Union(int x,int y){
int px=Find(x),py=Find(y);
if(px!=py){
parent[py]=px;
count--;
}
}
int Num(){
return count;
}
};
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int n=isConnected.size();
DJset s(n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(isConnected[i][j]==1)
s.Union(i,j);
}
}
return s.Num();
}
};
再贴上按秩合并的并查集代码。
class DJset {
private:
int* parent;//父指针数组
int* rank;
int count;
public:
DJset(int N) {
parent = new int[N];
rank = new int[N];
for (int i = 0; i < N; i++) {
parent[i] = i;
rank[i] = 1;
}
count = N;
}
int find(int x) {
if (parent[x] == x)
return x;
else
return find(parent[x]);
}
void merge(int i, int j) {
int x = find(i), y = find(j);
if (x == y)
return;
if (rank[x] <= rank[y])
parent[x] = y;
else
parent[y] = x;
if (rank[x] == rank[y] && x != y)
rank[y]++;//如果深度相同且根节点不同,则新的根节点的深度+1
count--;
}//按秩合并
int print_count() {
return count;
}
};
路径压缩的find函数
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]);//路径压缩
return parent[x];
}
部分代码来自https://zhuanlan.zhihu.com/p/93647900/,回顾按秩合并和路径压缩也可参考这篇文章。
2.统计子岛屿(DFS)
今天做了好几道图的深搜(广搜)题,思想都是一样的,贴一道DFS上来。
BFS要用到队列,有机会再练吧。
题目描述:
给你两个 m x n 的二进制矩阵 grid1 和 grid2 ,它们只包含 0 (表示水域)和 1 (表示陆地)。一个 岛屿 是由 四个方向 (水平或者竖直)上相邻的 1 组成的区域。任何矩阵以外的区域都视为水域。
如果 grid2 的一个岛屿,被 grid1 的一个岛屿 完全 包含,也就是说 grid2 中该岛屿的每一个格子都被 grid1 中同一个岛屿完全包含,那么我们称 grid2 中的这个岛屿为 子岛屿 。
请你返回 grid2 中 子岛屿 的 数目 。
难度:中等
题目地址
题解:
class Solution {
int dirs[4][2]={{1,0},{-1,0},{0,-1},{0,1}};
int m,n;
bool r;
public:
int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {
int ans=0;
m=grid1.size(),n=grid1[0].size();
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(grid2[i][j]==1){
r=true;
dfs(grid1,grid2,i,j);
if(r)
ans++;
}
}
}
return ans;
}
void dfs(vector<vector<int>>& grid1,vector<vector<int>>& grid2,int x, int y){
if(x<0||y<0||x>=m||y>=n||grid2[x][y]!=1){
return;
}
grid2[x][y]=2;
if(grid1[x][y]!=1)
r=false;
for(auto dir:dirs){
dfs(grid1,grid2,x+dir[0],y+dir[1]);
}
}
};
3.每日一题:统计按位或能得到最大值的子集数目(DFS)
题目描述:
给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目 。
如果数组 a 可以由数组 b 删除一些元素(或不删除)得到,则认为数组 a 是数组 b 的一个 子集 。如果选中的元素下标位置不一样,则认为两个子集 不同 。
对数组 a 执行 按位或 ,结果等于 a[0] OR a[1] OR … OR a[a.length - 1](下标从 0 开始)。
难度:中等
数据范围:
- 1 <= nums.length <= 16
- 1 <= nums[i] <= 105
题目地址
题解:
排列问题,时间复杂度O(
2
n
2^n
2n)。
1. 代码来自官方题解。添加一些注释。
class Solution {
public:
int countMaxOrSubsets(vector<int>& nums) {
this->nums = nums;
this->maxOr = 0;//能得到的按位或的最大的值,就是将nums中所有的数按位或得到的数。
this->cnt = 0;
dfs(0, 0);
return cnt;
}
void dfs(int pos, int orVal) {//orVal是当前按位或得到的数
if (pos == nums.size()) {//dfs终结条件,遍历到末尾
if (orVal > maxOr) {
maxOr = orVal;//每次维护新的最大值
cnt = 1;
} else if (orVal == maxOr) {
cnt++;
}
return;
}
dfs(pos + 1, orVal| nums[pos]);//选择num[pos]
dfs(pos + 1, orVal);//不选num[pos]
}
private:
vector<int> nums;
int maxOr, cnt;
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/solution/tong-ji-an-wei-huo-neng-de-dao-zui-da-zh-r6zd/
2. 提前算出maxVal,每次比较curVal和maxVal的大小,不用动态更新。
class Solution {
vector<int> nums;
public:
int countMaxOrSubsets(vector<int>& nums) {
this->nums=nums;
int maxVal=0;
for(auto a:nums)
maxVal|=a;
return dfs(0,0,maxVal);
}
int dfs(int curIndex, int curValue, int maxVal){
if(curIndex==nums.size()){
return maxVal==curValue?1:0;
}
return dfs(curIndex+1,curValue|nums[curIndex],maxVal)+dfs(curIndex+1,curValue,maxVal);
}
};