Найти самые большие из них после установки координаты в один - PullRequest
1 голос
/ 22 марта 2019

Вопрос для интервью:

Вам дана сетка из нулей и единиц.Вы можете произвольно выбрать любую точку в этой сетке.Вы должны написать функцию, которая делает две вещи:

  1. Если вы выберете, например, координату (3,4), и она равна нулю, вам нужно перевернуть ее на единицу.Если это единица, вам нужно перевернуть ее в ноль.
  2. Вам нужно вернуть наибольшую непрерывную область с наибольшим количеством, т.е. те, которые должны быть как минимум связаны с другим.

Например,

[0,0,0,0]
[0,1,1,0]
[1,0,1,0] 

У нас самый большой регион из трех.У нас есть еще одна область, в которой есть только одна (находится по координатам (2,0)).

Вам нужно найти алгоритм, который решит эту проблему, и вы будете вызывать эту функцию много раз.Вы должны убедиться, что ваше амортизированное время выполнения является наименьшим, которого вы можете достичь.

Мое решение, которое имеет временную сложность: O (num_row * num_col) каждый раз, когда вызывается эта функция:

def get_all_coordinates_of_ones(grid):
    set_ones = set()
    for i in range(len(grid[0])):
        for j in range(len(grid)):
            if grid[i][j]:
               set_ones.add((i, j))

    return set_ones

def get_largest_region(x, y, grid):

    num_col = len(grid)
    num_row = len(grid[0])
    one_or_zero = grid[x][y]

    if not grid[x][y]:
       grid[x][y] = 1 - grid[x][y]

    # get the coordinates of ones in the grid
    # Worst Case O(num_col * num_row)
    coordinates_ones = get_all_coordinates_of_ones(grid)

    while coordinates_ones:
       queue = collections.deque([coordinates_ones.pop()])
       largest_one = float('-inf')
       count_one = 1
       visited = set()
       while queue:
           x, y = queue.popleft()
           visited.add((x, y))
           for new_x, new_y in ((x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)):
               if (0 <= new_x < num_row and 0 <= new_y < num_col):
                   if grid[new_x][new_y] == 1 and (new_x, new_y) not in visited:
                       count_one += 1
                       if (new_x, new_y) in coordinates_ones:-
                           coordinates_ones.remove((new_x, new_y))
                       queue.append((new_x, new_y))
       largest_one = max(largest_one, count_one)
    return largest_one

Мои предложенные модификации:

Использование Union Find по рангу.Обнаружена проблема.Объедините все те, которые находятся рядом друг с другом.Теперь, когда одна из координат перевернута, например, с нуля на одну, мне нужно будет удалить эту координату из области, к которой она подключена.

Вопросы:

  1. Какой самый быстрый алгоритм с точки зрения сложности времени?
  2. Использование Union Find с рангом влечет за собой удаление узла.Это способ улучшить сложность времени?Если да, есть ли реализация удаления узла в объединении поиска в Интернете?

------------------------ РЕДАКТИРОВАТЬ---------------------------------

Должны ли мы всегда вычитать один из степени из суммы (степень-1 каждой «вырезанной» вершины).Вот два примера: первый, где нам нужно вычесть один, и второй, где нам не нужно вычитать один:

Пример дерева выреза блока 1

Вырезвершина - это вершина B. Степень вершины B в дереве разрезов блоков равна 2.

Сумма (количество элементов каждой вершины «блока»): 2 (A, B) + 1 (B) + 3 (B,C, D) = 6

Сумма (степень каждой вершины среза): 1 (B)

Размер среза блока: 6 - 1 = 5, но должно быть 4 (A. B, C, D, E, F).Здесь нужно вычесть еще одну.

Пример дерева среза блока 2

Сумма (мощность каждой вершины блока): 3 (A, B, C) +1 (C) + 1 (D) + 3 (D, E, F) = 8

Сумма (степень каждой «вырезанной» вершины): 2 (C и D)

Блокразмер среза: 8 - 2 = 6, что (A. B, C, D, E, F).Здесь не нужно вычитать один.

1 Ответ

1 голос
/ 22 марта 2019

без предварительной обработки:

  1. Переверните ячейку в матрице.
  2. Рассмотрим матрицу как график, где каждый '1' представляет узел, а соседние узлы соединены ребром.
  3. Найти все подключенных компонентов . Для каждого подключенного компонента - сохранить его мощность.
  4. Вернуть наивысшую мощность.

Обратите внимание, что O (V) = O (E) = O (num_row * num_col).

Шаг 3 принимает O (V + E) = O (num_row * num_col), что аналогично вашему решению.

Вы должны найти алгоритм, который решит эту проблему, где вы будете вызывать эту функцию много раз. Вы должны убедиться, что ваше амортизированное время пробега является самым низким, которого вы можете достичь.

Это указывает на то, что вы можете извлечь выгоду из предварительной обработки:

Препроцессирование:

  1. Рассмотрим исходную матрицу в виде графика G , где каждый '1' представляет узел, а соседние узлы соединены ребром.
  2. Найти все подключенных компонентов
  3. Построить набор из срубленных деревьев (раздел 5.2) из ​​ G (также здесь , здесь и здесь ) (одно дерево выреза для каждого подключенного компонента G ). Конструкция: см. здесь .

Обработка:

Если перевернуть ячейку «0» на «1»:

  • Найти соседние подключенные компоненты (от 0 до 4)
  • Удалите старые деревья вырубленных блоков, создайте новое дерево вырубленных блоков для объединенного компонента (возможна оптимизация: в некоторых случаях прежнее дерево может обновляться вместо реконструкции).

Если вы перевернете ячейку '1' на '0':

  • Если эта ячейка является «вырезанной» в дереве срезанных блоков:
    • удалить его из дерева срезов
    • удалить его из каждой соседней "вырезанной" вершины
    • разбить дерево срубов на несколько деревьев срубов
  • В противном случае (эта ячейка является частью только одной «блочной вершины»)
    • удалить его из вершины 'блока'; если пусто - удалить вершину. Если блок-срез дерева пуст - уберите его из набора деревьев.

Размер дерева среза блока = сумма (количество элементов каждой вершины блока) - сумма (соседний_блок-1 каждой вершины среза).

Деревья с вырубкой блоков не «хорошо известны» как другие структуры данных, поэтому я не уверен, имел ли это в виду интервьюер. Если это так - они действительно ищут кого-то с большим опытом работы с графовыми алгоритмами.

...