今天我们将在豆包MarsCode AI刷题平台上,完成《魔幻世界中的安全区计算》与《小C的mex查询》这两个算法问题,通过这些练习提升用户解决此类问题的能力
《魔幻世界中的安全区计算》题面如下:
问题理解
很常规的图遍历问题,不知道为什么难度标的是困难;需要计算在一个 n x m 的二维数组中,有多少个由相邻的、危险程度小于等于 X 的格子组成的安全区。
数据结构选择
使用二维数组 a 来表示异世界的危险程度,并使用深度优先搜索(DFS)来遍历和标记安全区。
算法步骤
- 初始化:定义一个
color变量,用于标记不同的安全区。初始值为-1,每发现一个新的安全区,color减一。 - 遍历二维数组:对于每个格子,如果其危险程度在
[0, X]范围内,则将其标记为当前的color,并使用 DFS 递归地标记与之相邻的所有安全格子。 - DFS 函数:
dfs函数用于递归地标记相邻的安全格子。它检查当前格子的四个方向(上下左右),如果相邻格子是安全的,则继续递归标记。 - 计算安全区数量:最终,
color的绝对值减一即为安全区的数量。
具体实现
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int path[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
void dfs(int n, int m, int X, std::vector<std::vector<int>>& a, int x,int y, int color){
for(int i=0;i<4;i++){
int nx = x + path[i][0], ny = y + path[i][1];
if(nx<0 || nx>=n || ny<0 || ny>=m){
continue;
}
if(a[nx][ny] < 0 || a[nx][ny]>X){
continue;
}
a[nx][ny] = color;
dfs(n,m,X,a,nx,ny,color);
}
}
int solution(int n, int m, int X, std::vector<std::vector<int>>& a) {
int color = -1;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(a[i][j] >=0 && a[i][j]<=X){
a[i][j] = color;
dfs(n,m,X,a,i,j,color);
color--;
}
}
}
return -color-1; // 返回安全区的数量
}
int main() {
std::vector<std::vector<int>> a1 = {{2, 3, 3}, {3, 3, 3}, {3, 3, 3}};
std::vector<std::vector<int>> a2 = {{6, 6}, {6, 4}};
std::vector<std::vector<int>> a3 = {{1, 2, 2}, {2, 3, 3}, {3, 4, 5}};
std::cout << (solution(3, 3, 4, a1) == 1) << std::endl;
std::cout << (solution(2, 2, 5, a2) == 1) << std::endl;
std::cout << (solution(3, 3, 3, a3) == 1) << std::endl;
return 0;
}
《小C的mex查询》题面如下:
问题理解
题目要求对一个空集进行多次操作,每次操作是将一个区间 [l, r] 内的所有整数添加到集合中,并在每次操作后输出当前集合的 mex(即集合中最小的未出现的非负整数)。
算法与数据结构选择
首先这道题当然可以选择使用线段树来实现,但是线段树的代码比较多,为了偷懒,这次我们选择使用bitset这个数据结构实现;bitset 是 C++ 标准库提供的一种固定大小的位向量。每个位可以是 0 或 1,适用于位级操作。bitset 提供了多种位操作方法,如按位与、按位或、按位异或等。
关键操作及复杂度分析
-
区间更新:
-
使用位移操作一次性更新区间
[l, r]。 -
具体操作:
bits |= bitset<MAXN>((1ull << (r - l + 1)) - 1) << l; -
复杂度分析:
- 生成一个由
l到r位全部为 1 的bitset:bitset<MAXN>((1ull << (r - l + 1)) - 1)的复杂度是 O(1),因为bitset的按位操作都是常数时间。
- 生成一个由
-
因此,区间更新的总复杂度是 O(q)。
-
-
计算 mex:
-
由 0 开始,找到第一个未被标记的数字。
-
具体操作:
while(bits.test(curMex)){ curMex++; } -
复杂度分析:
current_mex最多需要由 0 一直增加到MAXN,复杂度为 O(MAXN)。
-
具体实现
#include <bits/stdc++.h>
#include <bitset>
#include <vector>
using namespace std;
const int MAXN = 1000006;
vector<int> solution(int qLen, vector<vector<int>> queries) {
// write code here
vector<int> ret;
bitset<MAXN> bits;
int curMex=0;
for(auto& q : queries){
bits |= bitset<MAXN>((1ull << (q[1] - q[0]+1)) - 1) << q[0];
while(bits.test(curMex)){
curMex++;
}
ret.push_back(curMex);
}
return ret; // Placeholder
}
int main() {
cout << (solution(4, {{1, 3}, {7, 8}, {0, 5}, {3, 6}}) == vector<int>{0, 0, 6, 9}) << endl;
cout << (solution(3, {{0, 2}, {3, 4}, {6, 10}}) == vector<int>{3, 5, 5}) << endl;
cout << (solution(2, {{2, 5}, {7, 9}}) == vector<int>{0, 0}) << endl;
return 0;
}
总体复杂度
-
处理 q 次查询:
- 每次查询的区间更新复杂度是 O(1),总体处理查询的复杂度为O(q)。
-
计算mex:
- 总体计算 mex 的复杂度在最坏情况下是 O(MAXN)。
-
总体复杂度:O(q + MAXN)
借助豆包MarsCode AI刷题平台,我们不仅高效地解决了《魔幻世界中的安全区计算》和《小C的mex查询》,还加深了对相关算法和数据结构的理解,后续会借助豆包MarsCode AI给大家展示更多题目的解法。