알고리즘/leetcode
[leetcode] 733. Flood Fill
chinodaiski
2025. 2. 5. 11:06
문제 : https://leetcode.com/problems/flood-fill/description/
Solution
인자로 받은 위치의 번호로부터 시작하여 4방향으로 인접한 위치에 같은 번호가 있을 경우 번호들을 모두 다른 값으로 바꾸는 문제이다. Flood Fill이라는 이름답게 이동할 수 있는 모든 위치를 찾는 문제가 보면 된다.
#include <iostream>
#include <vector>
#include <queue>
class Solution
{
public:
// 인자로 2차원 배열, 시작 위치(sr, sc), 변경하고자하는 색상 을 받는다.
// 시작 위치에 있는 색상과 인접한 같은 색상을 인자로 받은 색상으로 변경하고, 변경된 2차원 배열을 반환하는 문제이다.
std::vector<std::vector<int>> floodFill(std::vector<std::vector<int>>& image, int sr, int sc, int color)
{
// 풀이 방법은 2차원에서 인접한 방향(4 또는 8 방향)으로 움직이며 자신과 같은 모든 번호를 찾아 변경하면 된다.
// 또한 한번 확인한 인덱스는 굳이 다시 확인할 필요가 없으니 이동할 위치의 인덱스가 바뀐 인덱스라면 넘어간다.
// 방식은 2가지가 있는데, DFS를 사용한 재귀, BFS를 사용한 큐 방식이다.
// 인자로 받은 image의 중복 이동 방지를 위해 복사한다.
// 이후 모든 요소를 0으로 초기화한다.
copiedImage = image;
for (auto& row : copiedImage) {
std::fill(row.begin(), row.end(), 0);
}
// 1. DFS를 사용한 재귀 방식
//CheckAdjacentIndexRecursive(image, sc, sr, color, image[sr][sc]);
// 2. BFS를 사용한 큐 방식
//CheckAdjacentIndexQueue(image, sc, sr, color, image[sr][sc]);
return image;
}
// 인자로 받은 배열에서 현재 위치 기준 상하좌우를 확인하여 같은 색상이라면 색상을 바꾸는 함수
void CheckAdjacentIndexRecursive(std::vector<std::vector<int>>& image, int x, int y, int color, int originalColor)
{
// 세로 길이 확인
if (image.empty() || y < 0 || y >= image.size())
return;
// 가로 길이 확인
if (image[0].empty() || x < 0 || x >= image[0].size())
return;
// 만약 현재 위치에 있는 색상이 originalColor라면
if (copiedImage[y][x] != 1 && image[y][x] == originalColor)
{
// 색상을 바꾸고, 이동했다는 표시를 남긴다.
image[y][x] = color;
copiedImage[y][x] = 1;
CheckAdjacentIndexRecursive(image, x, y - 1, color, originalColor); // 상
CheckAdjacentIndexRecursive(image, x, y + 1, color, originalColor); // 하
CheckAdjacentIndexRecursive(image, x - 1, y, color, originalColor); // 좌
CheckAdjacentIndexRecursive(image, x + 1, y, color, originalColor); // 우
}
}
// 인자로 받은 배열에서 현재 위치 기준 상하좌우를 확인하여 같은 색상이라면 색상을 바꾸는 함수
void CheckAdjacentIndexQueue(std::vector<std::vector<int>>& image, int x, int y, int color, int originalColor)
{
q.push(std::make_pair(x, y));
while (!q.empty())
{
const auto& index = q.front();
x = index.first;
y = index.second;
if (
y < 0 || y >= image.size() || // 세로 위치 확인
x < 0 || x >= image[0].size() // 가로 위치 확인
)
{
;
}
else
{
// 만약 현재 위치에 있는 색상이 originalColor라면
if (copiedImage[y][x] != 1 && image[y][x] == originalColor)
{
// 색상을 바꾸고, 이동했다는 표시를 남긴다.
image[y][x] = color;
copiedImage[y][x] = 1;
// 확인해야하는 위치 넣기
q.push(std::make_pair(x, y - 1)); // 상
q.push(std::make_pair(x, y + 1)); // 하
q.push(std::make_pair(x - 1, y)); // 좌
q.push(std::make_pair(x + 1, y)); // 우
}
}
// 현재 위치 확인했으니 넘김
q.pop();
}
}
private:
std::vector<std::vector<int>> copiedImage;
std::queue<std::pair<int, int>> q;
};
int main() {
std::vector<std::vector<int>> image = { {0,0,0},{1,0,0} };
Solution sol;
sol.floodFill(image, 1, 0, 2);
for (int i = 0; i < image.size(); ++i)
{
for (int j = 0; j < image[0].size(); ++j)
{
std::cout << image[i][j] << " ";
}
std::cout << "\n";
}
return 0;
}
예제는 주석 처리되어 있는 부분을 활성화시키면 된다.
// 1. DFS를 사용한 재귀 방식
//CheckAdjacentIndexRecursive(image, sc, sr, color, image[sr][sc]);
// 2. BFS를 사용한 큐 방식
//CheckAdjacentIndexQueue(image, sc, sr, color, image[sr][sc]);
이 문제의 시간 복잡도는 O(N * M)인데, 이는 2차원 배열에서 이동할 수 있는 모든 위치에 한번씩 이동하기 때문이다.
공간 복잡도 또한 O(N * M)인데, BFS(queue) 방식이던, DFS(재귀) 방식이던 최악의 경우 2차원 배열의 모든 위치에 접근하기 때문이다.
Submission Detail
DFS : https://leetcode.com/submissions/detail/1531681396/
BFS : https://leetcode.com/submissions/detail/1531695553/