题目
问题描述
小C在一个大小为 n * m 的棋盘状土地上发现了三个国家的势力分布s。每个格子上都有一个数字,表示该格子的归属国家。上下左右相邻且属于同一个国家的格子被认为是同一股势力。现在小C想知道,这片土地上总共有多少股不同的势力。
你需要编写一个程序来计算土地上总共的势力股数。
测试样例
样例1:
输入:
n = 4 ,m = 4 ,s = ["1122", "1222", "3111", "3333"]输出:4
样例2:
输入:
n = 2 ,m = 2 ,s = ["11", "11"]输出:1
样例3:
输入:
n = 3 ,m = 3 ,s = ["123", "123", "123"]输出:3
解题思路
深度优先搜索DFS
1. 遍历棋盘
我们需要逐行逐列检查每一个格子:
- 如果格子未访问过,说明它是一个新势力区域的起点。
- 如果格子已经访问过,则跳过它,避免重复计数。
2. 使用 DFS 搜索连通区域
DFS 是一种递归方法,可以很好地找到一个区域的所有相邻格子:
- 从当前格子开始,递归检查其上下左右四个方向。
- 如果某个方向的格子属于同一势力(相同的数字),继续递归搜索,并标记为已访问。
3. 标记已访问的格子
为了防止重复计数,我们可以直接将访问过的格子标记为特殊字符,例如 '.'。
4. 势力区域计数
每次触发新的 DFS 时,将计数器 ans 加 1。最后返回 ans 的值即答案。
例如:
1 1 2 2
1 2 2 2
3 1 1 1
3 3 3 3
首先遍历到s[0][0]的位置,从该位置开始深度优先搜索,得到结果
. . 2 2
. 2 2 2
3 1 1 1
3 3 3 3
结束后继续遍历到s[0][2],开始深度优先搜索,得到结果
. . . .
. . . .
3 1 1 1
3 3 3 3
以此类推……
Code
#include <iostream>
#include <vector>
#include <string>
int dx[4] = {0, 0, -1, 1};
int dy[4] = {1, -1, 0, 0};
void dfs(const int& n, const int& m, const int x, const int y, std::vector<std::string>& s, const char c) {
s[x][y] = '.';
for (int i = 0; i < 4; i++) {
int destx = x + dx[i];
int desty = y + dy[i];
if (destx >= 0 && destx < n && desty >= 0 && desty < m && s[destx][desty] == c)
dfs(n, m, destx, desty, s, c);
}
}
int solution(int n, int m, std::vector<std::string> s) {
int ans = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (s[i][j] != '.'){
ans++;
dfs(n, m, i, j, s, s[i][j]);
}
return ans;
}
int main() {
std::cout << (solution(4, 4, {"1122", "1222", "3111", "3333"}) == 4) << std::endl;
std::cout << (solution(2, 2, {"11", "11"}) == 1) << std::endl;
std::cout << (solution(3, 3, {"123", "123", "123"}) == 3) << std::endl;
}
复杂度
-
时间复杂度
- 每个格子最多会被访问一次(被DFS标记为
'.'),因此总时间复杂度为O(n * m),其中n是棋盘的行数,m是列数。
- 每个格子最多会被访问一次(被DFS标记为
-
空间复杂度
- 递归调用栈的最大深度为棋盘的总面积
n * m(极端情况下,所有格子都属于同一势力区域),因此最坏情况下的空间复杂度为O(n * m)。
- 递归调用栈的最大深度为棋盘的总面积