Гуру тест про порядок элементов в иерархии

Есть некоторый иерархический справочник, иерархия элементов. У каждого элемента есть поле «Позиция» (может быть дробным и отрицательным). Элементы в пределах одного родителя должны быть пронумерованы в поле «Позиция» по порядку с единицы с шагом один: 1, 2, … N

Таким образом, например, чтобы поменять порядок элементов с позициями 2 и 3 мы можем элементу с позицией 2 установить позицию 2,5 и вызвать процедуру исправления порядка.

Не буду давать подсказки и наводящие мысли, просто жду от вас идей оптимальной реализации алгоритма проверки и изменения порядка. Это гуру-тест, который, кстати, можно давать на собеседованиях.

Пример: в группе с названием Алкоголь есть элементы с позициями:

  • Пиво 1
  • Водка 2
  • Эль 3

Я меняю:

  • Пиво 2.5
  • Водка 2
  • Эль 3

Система должна пересчитать по всей номенклатуре и сделать:

  • Водка 1
  • Пиво 2
  • Эль 3

Причем найти отклонения и сделать изменения максимально эффективно.

По сути можно упростить вопрос — как запросом найти группы, где порядок 1, 2, … N нарушен?

Вот еще пример:

Есть группа Алкоголь 1, в ней элементы:
Водка 2
Пиво 2.5
Эль 3
Есть группа Мясное 2, в ней элементы:
Сосиски 3
Ветчина 5
Есть группа Напитки 3, в ней элементы:
Квас 1
Сок 2

Нужно по этому пример найти запросом группы, где нарушен порядок 1, 2, N.
Правильный ответ: Алкоголь, Мясное.
Неправильные ответы: Напитки, Корень.

Обсуждение задачи на Мисте. 1сники не справились, задал задачу на Хабре.

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

комментария 2

  1. Дыкелыпалы:

    Для решения задачи поиска групп, в которых нарушен порядок элементов, можно использовать SQL-запрос, который будет анализировать позиции элементов в каждой группе. Основная идея заключается в том, чтобы найти группы, где хотя бы один элемент имеет позицию, которая не соответствует порядку 1, 2, …, N.

    SQL-запрос для поиска групп с нарушенным порядком
    sql
    Copy
    SELECT DISTINCT parent_id
    FROM (
    SELECT
    parent_id,
    position,
    ROW_NUMBER() OVER (PARTITION BY parent_id ORDER BY position) AS expected_position
    FROM elements
    ) AS subquery
    WHERE position expected_position;
    Объяснение SQL-запроса
    Подзапрос:

    Используется функция ROW_NUMBER(), чтобы назначить ожидаемую позицию (expected_position) для каждого элемента в пределах его родительской группы.

    PARTITION BY parent_id разбивает данные на группы по родительскому идентификатору.

    ORDER BY position сортирует элементы в каждой группе по их текущей позиции.

    Основной запрос:

    Сравнивает текущую позицию (position) с ожидаемой позицией (expected_position).

    Если они не совпадают, это означает, что порядок нарушен.

    DISTINCT parent_id используется для вывода уникальных идентификаторов групп, где обнаружены нарушения.

    Пример данных
    Предположим, у нас есть таблица elements со следующими данными:

    id parent_id name position
    1 1 Водка 2
    2 1 Пиво 2.5
    3 1 Эль 3
    4 2 Сосиски 3
    5 2 Ветчина 5
    6 3 Квас 1
    7 3 Сок 2
    Результат запроса
    Запрос вернет:

    parent_id
    1
    2
    Это означает, что группы с parent_id = 1 (Алкоголь) и parent_id = 2 (Мясное) имеют нарушения в порядке элементов.

    Сложность (Big O)
    Временная сложность:

    ROW_NUMBER() имеет сложность O(N log N) из-за сортировки.

    Основной запрос проверяет каждую строку, поэтому его сложность O(N).

    Общая сложность: O(N log N).

    Пространственная сложность:

    Зависит от реализации базы данных, но в целом O(N) для хранения промежуточных данных.

    C++ Реализация
    Если требуется реализация на C++, то можно использовать следующий подход:

    cpp
    Copy
    #include
    #include
    #include
    #include

    struct Element {
    int id;
    int parent_id;
    std::string name;
    double position;
    };

    void find_groups_with_invalid_order(const std::vector& elements) {
    std::map<int, std::vector> grouped_elements;

    // Группируем элементы по parent_id
    for (const auto& elem : elements) {
    grouped_elements[elem.parent_id].push_back(elem);
    }

    // Проверяем каждую группу
    for (const auto& group : grouped_elements) {
    const auto& group_elements = group.second;
    std::vector positions;

    // Собираем позиции
    for (const auto& elem : group_elements) {
    positions.push_back(elem.position);
    }

    // Сортируем позиции
    std::vector sorted_positions = positions;
    std::sort(sorted_positions.begin(), sorted_positions.end());

    // Проверяем, совпадают ли позиции с отсортированными
    bool is_valid = true;
    for (size_t i = 0; i < positions.size(); ++i) {
    if (positions[i] != sorted_positions[i]) {
    is_valid = false;
    break;
    }
    }

    // Если порядок нарушен, выводим parent_id
    if (!is_valid) {
    std::cout << "Группа с parent_id = " << group.first << " имеет нарушенный порядок." << std::endl;
    }
    }
    }

    int main() {
    std::vector elements = {
    {1, 1, «Водка», 2},
    {2, 1, «Пиво», 2.5},
    {3, 1, «Эль», 3},
    {4, 2, «Сосиски», 3},
    {5, 2, «Ветчина», 5},
    {6, 3, «Квас», 1},
    {7, 3, «Сок», 2}
    };

    find_groups_with_invalid_order(elements);

    return 0;
    }
    Объяснение C++ кода
    Группировка элементов:

    Элементы группируются по parent_id с использованием std::map.

    Проверка порядка:

    Для каждой группы собираются позиции и сортируются.

    Сравниваются исходные позиции с отсортированными.

    Вывод результата:

    Если обнаружено несоответствие, выводится parent_id группы.

    Сложность (Big O)
    Временная сложность:

    Группировка: O(N).

    Сортировка: O(N log N).

    Проверка: O(N).

    Общая сложность: O(N log N).

    Пространственная сложность:

    O(N) для хранения групп и позиций.

    Этот подход эффективно решает задачу и может быть легко адаптирован для работы с реальными данными.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *