План курса / Все задачи / Алгоритмы и структуры данных
Мозаика
легко
Дана цветная мозаика в виде двумерного массива grid, где каждое число обозначает цвет клетки. Нужно найти цвет, у которого максимальное количество компонент связности. Гарантируется, что такой цвет единственный.
Один компонент связности - это группа соединённых клеток одного цвета, которые соседствуют только по вертикали или горизонтали (по диагонали клетки не считаются соединёнными).
Пример:
Ввод: grid =
[[8,8,2,2,1]
,[8,8,2,1,1]
,[2,2,2,2,1]
,[1,1,8,8,8]
,[1,8,8,1,8]]
Вывод: 1
Объяснение: у цвета "1" - 3 компоненты (наибольшее число компонент).
Ограничения:
len(grid) >= 1
len(grid[i]) >= 1
using System;
using System.Collections.Generic;
public class Solution
{
public static bool InBound(int i, int j, List<List<int>> grid)
{
return 0 <= i && i < grid.Count && 0 <= j && j < grid[0].Count;
}
public static void Dfs(int i, int j, int needsColor, List<List<bool>> used, List<List<int>> grid)
{
if (!InBound(i, j, grid) || needsColor != grid[i][j] || used[i][j])
{
return;
}
used[i][j] = true;
// Используем цикл для проверки соседних клеток
var nextSteps = new List<List<int>> { new List<int> { i, j + 1 }, new List<int> { i, j - 1 }, new List<int> { i + 1, j }, new List<int> { i - 1, j } };
foreach (var nextStep in nextSteps)
{
Dfs(nextStep[0], nextStep[1], needsColor, used, grid);
}
}
public static int MaxComponents(List<List<int>> grid)
{
var used = new List<List<bool>>(grid.Count);
for (int i = 0; i < grid.Count; i++)
{
used.Add(new List<bool>(new bool[grid[0].Count]));
}
// Используем словарь для хранения счётчиков цветов
var colorsCount = new Dictionary<int, int>();
for (int i = 0; i < grid.Count; i++)
{
for (int j = 0; j < grid[i].Count; j++)
{
if (!used[i][j])
{
int color = grid[i][j];
if (!colorsCount.ContainsKey(color))
{
colorsCount[color] = 0;
}
// Увеличиваем количество компонент для текущего цвета
colorsCount[color]++;
Dfs(i, j, color, used, grid);
}
}
}
// Находим максимальное количество компонентов
int maxColorsCount = 0;
foreach (var count in colorsCount.Values)
{
maxColorsCount = Math.Max(maxColorsCount, count);
}
// Находим цвет с максимальным количеством компонентов
foreach (var kvp in colorsCount)
{
if (kvp.Value == maxColorsCount)
{
return kvp.Key;
}
}
return 0;
}
}
#include <vector>
#include <unordered_map>
using namespace std;
// Проверяет, находятся ли индексы i и j в пределах матрицы
bool inBound(int i, int j, const vector<vector<int>>& grid) {
return 0 <= i && i < grid.size() && 0 <= j && j < grid[0].size();
}
// Рекурсивный обход в глубину (DFS)
void dfs(int i, int j, int needsColor, vector<vector<bool>>& used, const vector<vector<int>>& grid) {
// Если клетка выходит за границы, имеет другой цвет или уже посещена, выходим
if (!inBound(i, j, grid) || needsColor != grid[i][j] || used[i][j]) {
return;
}
// Помечаем клетку как посещённую
used[i][j] = true;
// Перебираем соседние клетки (вверх, вниз, влево, вправо)
vector<pair<int, int>> nextSteps = {{i, j + 1}, {i, j - 1}, {i + 1, j}, {i - 1, j}};
for (const auto& nextStep : nextSteps) {
dfs(nextStep.first, nextStep.second, needsColor, used, grid);
}
}
// Основная функция для поиска максимального количества компонент
int maxComponents(const vector<vector<int>>& grid) {
// Инициализация массива для отслеживания посещённых клеток
vector<vector<bool>> used(grid.size(), vector<bool>(grid[0].size(), false));
// Словарь для подсчёта количества компонент каждого цвета
unordered_map<int, int> colorsCount;
// Перебор всех клеток матрицы
for (int i = 0; i < grid.size(); ++i) {
for (int j = 0; j < grid[i].size(); ++j) {
// Если клетка ещё не посещена
if (!used[i][j]) {
int color = grid[i][j];
// Увеличиваем счётчик для текущего цвета
colorsCount[color]++;
// Обходим все клетки, связанные с текущей
dfs(i, j, color, used, grid);
}
}
}
// Находим максимальное количество компонент
int max_colorsCount = 0;
for (const auto& count : colorsCount) {
max_colorsCount = max(max_colorsCount, count.second);
}
// Возвращаем цвет с максимальным количеством компонент
for (const auto& count : colorsCount) {
if (count.second == max_colorsCount) {
return count.first;
}
}
// Если компонент нет
return 0;
}
package main
// Проверяет, находятся ли индексы i и j в пределах матрицы
func inBound(i, j int, grid [][]int) bool {
return i >= 0 && i < len(grid) && j >= 0 && j < len(grid[0])
}
// Рекурсивный обход в глубину (DFS)
func dfs(i, j, needsColor int, used [][]bool, grid [][]int) {
// Если клетка выходит за границы, имеет другой цвет или уже посещена, выходим
if !inBound(i, j, grid) || needsColor != grid[i][j] || used[i][j] {
return
}
// Помечаем клетку как посещённую
used[i][j] = true
// Перебираем соседние клетки (вверх, вниз, влево, вправо)
nextSteps := [][]int{{i, j + 1}, {i, j - 1}, {i + 1, j}, {i - 1, j}}
for _, nextStep := range nextSteps {
dfs(nextStep[0], nextStep[1], needsColor, used, grid)
}
}
// Основная функция для поиска максимального количества компонент
func maxComponents(grid [][]int) int {
// Инициализация массива для отслеживания посещённых клеток
used := make([][]bool, len(grid))
for i := range used {
used[i] = make([]bool, len(grid[0]))
}
// Словарь для подсчёта количества компонент каждого цвета
colorsCount := make(map[int]int)
// Перебор всех клеток матрицы
for i := 0; i < len(grid); i++ {
for j := 0; j < len(grid[i]); j++ {
// Если клетка ещё не посещена
if !used[i][j] {
color := grid[i][j]
// Увеличиваем счётчик для текущего цвета
colorsCount[color]++
// Обходим все клетки, связанные с текущей
dfs(i, j, color, used, grid)
}
}
}
// Находим максимальное количество компонент
maxColorsCount := 0
for _, count := range colorsCount {
if count > maxColorsCount {
maxColorsCount = count
}
}
// Возвращаем цвет с максимальным количеством компонент
for color, count := range colorsCount {
if count == maxColorsCount {
return color
}
}
// Если компонент нет
return 0
}
import java.util.*;
public class Solution {
// Проверяет, находятся ли индексы i и j в пределах матрицы
public static boolean inBound(int i, int j, List<List<Integer>> grid) {
return 0 <= i && i < grid.size() && 0 <= j && j < grid.get(0).size();
}
// Рекурсивный обход в глубину (DFS)
public static void dfs(int i, int j, int needsColor, List<List<Boolean>> used, List<List<Integer>> grid) {
// Если клетка выходит за границы, имеет другой цвет или уже посещена, выходим
if (!inBound(i, j, grid) || needsColor != grid.get(i).get(j) || used.get(i).get(j)) {
return;
}
// Помечаем клетку как посещённую
used.get(i).set(j, true);
// Перебираем соседние клетки (вверх, вниз, влево, вправо)
int[][] nextSteps = {{i, j + 1}, {i, j - 1}, {i + 1, j}, {i - 1, j}};
for (int[] nextStep : nextSteps) {
dfs(nextStep[0], nextStep[1], needsColor, used, grid);
}
}
// Основная функция для поиска максимального количества компонент
public static int maxComponents(List<List<Integer>> grid) {
// Инициализация массива для отслеживания посещённых клеток
List<List<Boolean>> used = new ArrayList<>();
for (List<Integer> row : grid) {
List<Boolean> usedRow = new ArrayList<>();
for (int k = 0; k < row.size(); k++) {
usedRow.add(false);
}
used.add(usedRow);
}
// Словарь для подсчёта количества компонент каждого цвета
Map<Integer, Integer> colorsCount = new HashMap<>();
// Перебор всех клеток матрицы
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid.get(i).size(); j++) {
// Если клетка ещё не посещена
if (!used.get(i).get(j)) {
int color = grid.get(i).get(j);
// Увеличиваем счётчик для текущего цвета
colorsCount.put(color, colorsCount.getOrDefault(color, 0) + 1);
// Обходим все клетки, связанные с текущей
dfs(i, j, color, used, grid);
}
}
}
// Находим максимальное количество компонент
int maxColorsCount = Collections.max(colorsCount.values());
// Возвращаем цвет с максимальным количеством компонент
for (Map.Entry<Integer, Integer> entry : colorsCount.entrySet()) {
if (entry.getValue() == maxColorsCount) {
return entry.getKey();
}
}
// Если компонент нет
return 0;
}
}
from typing import List
def in_bound(i: int, j: int, grid: List[List[int]]) -> bool:
return 0 <= i < len(grid) and 0 <= j < len(grid[0])
def dfs(i: int, j: int, needs_color: int, used: List[List[bool]], grid: List[List[int]]) -> None:
if not in_bound(i, j, grid) or needs_color != grid[i][j] or used[i][j]:
return
used[i][j] = True
# Используем цикл для проверки соседних клеток
next_steps = [[i, j+1], [i, j-1], [i+1, j], [i-1, j]]
for next_step in next_steps:
dfs(next_step[0], next_step[1], needs_color, used, grid)
def max_components(grid: List[List[int]]) -> int:
used = [[False for _ in range(len(el))] for el in grid]
# Используем словарь для хранения счётчиков цветов
colors_count = {}
for i in range(len(grid)):
for j in range(len(grid[i])):
if not used[i][j]:
color = grid[i][j]
# Увеличиваем количество компонент для текущего цвета
colors_count[color] = colors_count.get(color, 0) + 1
dfs(i, j, color, used, grid)
# Находим максимальное количество компонентов
max_colors_count = max(colors_count.values())
print(max_colors_count, colors_count)
# Находим цвет с максимальным количеством компонентов
for color, count in colors_count.items():
if count == max_colors_count:
return color
return 0
// Проверяет, находятся ли индексы i и j в пределах матрицы
function inBound(i, j, grid) {
return 0 <= i && i < grid.length && 0 <= j && j < grid[0].length;
}
// Рекурсивный обход в глубину (DFS)
function dfs(i, j, needsColor, used, grid) {
// Если клетка выходит за границы, имеет другой цвет или уже посещена, выходим
if (!inBound(i, j, grid) || needsColor !== grid[i][j] || used[i][j]) {
return;
}
// Помечаем клетку как посещённую
used[i][j] = true;
// Перебираем соседние клетки (вверх, вниз, влево, вправо)
const nextSteps = [[i, j + 1], [i, j - 1], [i + 1, j], [i - 1, j]];
for (const nextStep of nextSteps) {
dfs(nextStep[0], nextStep[1], needsColor, used, grid);
}
}
// Основная функция для поиска максимального количества компонент
export function maxComponents(grid) {
// Инициализация массива для отслеживания посещённых клеток
const used = Array.from({ length: grid.length }, () => Array(grid[0].length).fill(false));
// Словарь для подсчёта количества компонент каждого цвета
const colorsCount = {};
// Перебор всех клеток матрицы
for (let i = 0; i < grid.length; i++) {
for (let j = 0; j < grid[i].length; j++) {
// Если клетка ещё не посещена
if (!used[i][j]) {
const color = grid[i][j];
// Увеличиваем счётчик для текущего цвета
colorsCount[color] = (colorsCount[color] || 0) + 1;
// Обходим все клетки, связанные с текущей
dfs(i, j, color, used, grid);
}
}
}
// Находим максимальное количество компонент
let maxColorsCount = 0;
for (const count of Object.values(colorsCount)) {
maxColorsCount = Math.max(maxColorsCount, count);
}
// Возвращаем цвет с максимальным количеством компонент
for (const [color, count] of Object.entries(colorsCount)) {
if (count === maxColorsCount) {
return parseInt(color);
}
}
// Если компонент нет
return 0;
}
Оценка сложности
Время: O(n * m), где n кол-во строк и m кол-во столбцов входного массива
Память: O(n * m), где n кол-во строк и m кол-во столбцов входного массива