У меня есть массив отсортированных (в порядке возрастания) элементов в качестве входных данных. Я хочу выяснить, составляют ли эти элементы серию, в которой каждый текущий элемент делится на все элементы, которые были до него. Это очевидное решение этой проблемы за O (n) время, о котором я мог подумать:

bool CheckArray(int arr[], int no_of_elements)
{
    if (no_of_elements == 1)
        return true;

    for (int i = 1; i < no_of_elements; i++)
        if (arr[i] % arr[i - 1] != 0)
            return false;
    return true;
}

Пример 1: Вход: 3 6 9 12 Выход: False

Пример 2: Вход: 3 6 12 Выход: True

Есть ли способ сделать это менее чем за O (N) время, хотя? Если да, то как?

6
Akshat Shrivastava 12 Фев 2020 в 15:30

2 ответа

Лучший ответ

Очевидно, вам нужен O (N) обход, чтобы получить true.

Оптимизация, которую вы можете сделать, - это получить false как можно скорее.

Я предполагаю (и думаю, что доказательство было бы трудным, но верно, если числа арифметически распределены), что смежные большие пары чисел ( a , b ) с меньшей вероятностью будут иметь форма ( a , na ) для целых n , чем меньшие числа. Следовательно, вы могли бы получить false быстрее, сначала рассмотрев большее число. Другими словами, выполнение цикла от последнего до первого элемента вполне может оказаться статистически более быстрым. Вы должны были бы составить профиль на типичных числовых сериях, которые представлены для вашей функции.

Кстати, ваша преамбула

if (no_of_elements == 1)
    return true;

Избыточно

5
Bathsheba 12 Фев 2020 в 13:01

Невозможно сделать это лучше, чем O (n).

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

Таким образом, у вас будет по крайней мере O (n).

6
Jeffrey 12 Фев 2020 в 12:40