复习hash表
区别set,unordered_set,multiset,map,unordered_map,multimap:
-
需要「有序性 / 范围查找」→ 选红黑树系列(set/map/multiset/multimap)
- 仅存唯一值,要有序 →
set - 存键值对,要有序 →
map - 存重复值,要有序 →
multiset - 存重复键的键值对,要有序 →
multimap
- 仅存唯一值,要有序 →
-
追求「极致查找效率」,无需有序 → 选哈希表系列(unordered_set/unordered_map)
- 仅存唯一值,要高效去重 / 判重 →
unordered_set - 存键值对,要高效查值 →
unordered_map
- 仅存唯一值,要高效去重 / 判重 →
-
补充:自定义类型存储
- 红黑树系列:需提供比较函数(如
<运算符) - 哈希表系列:需提供哈希函数 + 相等判断函数(如
==运算符)
- 红黑树系列:需提供比较函数(如
DFS求高山流水
#include<iostream>
#include<vector>
using namespace std;
//遍历方向数组
int dir[4][2]={-1, 0, 0, -1, 1, 0, 0, 1};
//dfs深度优先遍历递归数组,确定返回值为void
void dfs(vector<vector<int>> &graph,vector<vector<bool>> &visit,int x,int y){
//传参分别为遍历的图,访问数组,访问点的x,y坐标
//递归结束标志,访问到已访问的结点时返回
if(visit[x][y]==true) return;
//对传入的结点标记访问
visit[x][y]=true;
//执行单层递归逻辑,对四个方向分别进行深度优先遍历访问
for(int i=0;i<4;i++){
int nextx=x+dir[i][0];
int nexty=y+dir[i][1];
//进行越界判断
int row_num=graph.size();
int col_num=graph.empty()?0:graph[0].size();
if(nextx<0||nextx>=row_num||nexty<0||nexty>=col_num) continue;
//根据题设,可以反向由低到高访问
if(graph[x][y]<=graph[nextx][nexty])
dfs(graph,visit,nextx,nexty);
}
//循环完之后返回
return;
}
//设置主函数
int main(){
//读入矩阵
int n,m;
cout<<"输入行列"<<endl;
cin>>n>>m;
//初始化矩阵
vector<vector<int>> graph(n,vector<int>(m,0));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>graph[i][j];
}
}
//标记可以从第一组遍历的结点
vector<vector<bool>> firstgroup(n,vector<bool>(m,false));
//标记可以从第二组遍历的结点
vector<vector<bool>> secondgroup(n,vector<bool>(m,false));
//从行开始遍历,分别遍历最上行和最下行
for(int i=0;i<m;i++){
//遍历最上行,也就是第一组
dfs(graph,firstgroup,0,i);
//遍历最下行,也就时第二组
dfs(graph,secondgroup,n-1,i);
}
//从列开始遍历,分别遍历最左列和最右列
for(int i=0;i<n;i++){
//遍历最左列
dfs(graph,firstgroup,i,0);
//遍历最右列
dfs(graph,secondgroup,i,m-1);
}
//对比两组都可以访问的结点,输出
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(firstgroup[i][j]==true&&secondgroup[i][j]==true)
cout<<i<<" "<<j<<endl;
}
}
}
建造最大人工岛问题解答: 1.通过hash表对岛屿进行标记并快速映射查找 2.添加岛屿之后在四个方向进行遍历,把结果加入求最大值。
#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
using namespace std;
int n, m;
int count;
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y, int mark) {
if (visited[x][y] || grid[x][y] == 0) return; // 终止条件:访问过的节点 或者 遇到海水
visited[x][y] = true; // 标记访问过
grid[x][y] = mark; // 给陆地标记新标签
count++;
for (int i = 0; i < 4; i++) {
int nextx = x + dir[i][0];
int nexty = y + dir[i][1];
if (nextx < 0 || nextx >= n || nexty < 0 || nexty >= m) continue; // 越界了,直接跳过
dfs(grid, visited, nextx, nexty, mark);
}
}
int main() {
cin >> n >> m;
vector<vector<int>> grid(n, vector<int>(m, 0));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
vector<vector<bool>> visited(n, vector<bool>(m, false)); // 标记访问过的点
unordered_map<int ,int> gridNum;
int mark = 2; // 记录每个岛屿的编号
bool isAllGrid = true; // 标记是否整个地图都是陆地
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 0) isAllGrid = false;
if (!visited[i][j] && grid[i][j] == 1) {
count = 0;
dfs(grid, visited, i, j, mark); // 将与其链接的陆地都标记上 true
gridNum[mark] = count; // 记录每一个岛屿的面积
mark++; // 记录下一个岛屿编号
}
}
}
if (isAllGrid) {
cout << n * m << endl; // 如果都是陆地,返回全面积
return 0; // 结束程序
}
// 以下逻辑是根据添加陆地的位置,计算周边岛屿面积之和
int result = 0; // 记录最后结果
unordered_set<int> visitedGrid; // 标记访问过的岛屿
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
count = 1; // 记录连接之后的岛屿数量
visitedGrid.clear(); // 每次使用时,清空
if (grid[i][j] == 0) {
for (int k = 0; k < 4; k++) {
int neari = i + dir[k][1]; // 计算相邻坐标
int nearj = j + dir[k][0];
if (neari < 0 || neari >= n || nearj < 0 || nearj >= m) continue;
if (visitedGrid.count(grid[neari][nearj])) continue; // 添加过的岛屿不要重复添加
// 把相邻四面的岛屿数量加起来
count += gridNum[grid[neari][nearj]];
visitedGrid.insert(grid[neari][nearj]); // 标记该岛屿已经添加过
}
}
result = max(result, count);
}
}
cout << result << endl;
}
统计海岸线
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> grid(n, vector<int>(m, 0));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
int sum = 0; // 陆地数量
int cover = 0; // 相邻数量
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1) {
sum++; // 统计总的陆地数量
// 统计上边相邻陆地
if(i - 1 >= 0 && grid[i - 1][j] == 1) cover++;
// 统计左边相邻陆地
if(j - 1 >= 0 && grid[i][j - 1] == 1) cover++;
// 为什么没统计下边和右边? 因为避免重复计算
}
}
}
cout << sum * 4 - cover * 2 << endl;
}