Поиск подпоследовательностей.
От: steep8  
Дата: 27.05.24 06:51
Оценка:
По каналу связи передаётся последовательность целых неотрицательных чисел – показания прибора, полученные с интервалом в 1 мин. в течение T мин. (T – целое число). Прибор измеряет количество атмосферных осадков, полученное регистратором за минуту, предшествующую моменту регистрации, и передаёт это значение в условных единицах измерения.

Ученые анализируют последовательность и выявляют смежные диапазоны времени, содержащие не менее K измерений каждый, в которые выпало одинаковое количество осадков.

Определите, сколько таких смежных пар диапазонов есть в снятой последовательности.

в первой строке содержит натуральное число K – минимальное количество показаний в каждом из смежных диапазонов, а во второй – количество переданных показаний N (1 ≤ N ≤ 10 000, N >> K). В каждой из следующих N строк находится одно целое неотрицательное число, не превышающее 1000, обозначающее количество осадков за соответствующую минуту.

Пример данных:
2
8
1
2
3
4
1
1
2
5
При таких исходных данных количество смежных периодов с одинаковым количеством осадков 4: ((2, 3), (4, 1)), ((1, 2, 3), (4, 1, 1)), ((3, 4, 1), (1, 2, 5)), ((2, 3, 4), (1, 1, 2, 5)).

Пока мысли насчитать префиксных сумм и использовать их. Но эффективного алгоритма не придумывается что то.
Отредактировано 27.05.2024 6:53 steep8 . Предыдущая версия . Еще …
Отредактировано 27.05.2024 6:52 steep8 . Предыдущая версия .
Re: Поиск подпоследовательностей.
От: kov_serg Россия  
Дата: 27.05.24 09:04
Оценка:
Здравствуйте, steep8, Вы писали:

S>Пример данных:

S> 2
S> 8
S> 1
S> 2
S> 3
S> 4
S> 1
S> 1
S> 2
S> 5
S>При таких исходных данных количество смежных периодов с одинаковым количеством осадков 4: ((2, 3), (4, 1)), ((1, 2, 3), (4, 1, 1)), ((3, 4, 1), (1, 2, 5)), ((2, 3, 4), (1, 1, 2, 5)).

Диапазоны могут пересекаться? например: [1..6]=8+1+2+3+4+1=19 и [2..9]=1+2+3+4+1+1+2+5=19
Re[2]: Поиск подпоследовательностей.
От: steep8  
Дата: 27.05.24 10:07
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Диапазоны могут пересекаться? например: [1..6]=8+1+2+3+4+1=19 и [2..9]=1+2+3+4+1+1+2+5=19


нет, не могут.
Re[3]: Поиск подпоследовательностей.
От: kov_serg Россия  
Дата: 27.05.24 13:38
Оценка:
Здравствуйте, steep8, Вы писали:

_>>Диапазоны могут пересекаться? например: [1..6]=8+1+2+3+4+1=19 и [2..9]=1+2+3+4+1+1+2+5=19


S>нет, не могут.

И как должен выглядеть результат для [1,1,1,1,1,1,1,1,1,1,1,1] ?
Re: Поиск подпоследовательностей.
От: Буравчик Россия  
Дата: 27.05.24 21:55
Оценка:
Здравствуйте, steep8, Вы писали:

S>Пока мысли насчитать префиксных сумм и использовать их. Но эффективного алгоритма не придумывается что то.


O(N^2) достаточно эффективный? Быстрее что-то не придумывается (если вообще возможно).
Best regards, Буравчик
Re[2]: Поиск подпоследовательностей.
От: bnk СССР http://unmanagedvisio.com/
Дата: 27.05.24 22:05
Оценка:
Здравствуйте, Буравчик, Вы писали:

S>>Пока мысли насчитать префиксных сумм и использовать их. Но эффективного алгоритма не придумывается что то.


Б>O(N^2) достаточно эффективный? Быстрее что-то не придумывается (если вообще возможно).


Чат GPT говорит что знает решение за O(N)
Re[3]: Поиск подпоследовательностей.
От: Буравчик Россия  
Дата: 27.05.24 22:47
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Чат GPT говорит что знает решение за O(N)


Давай его сюда (решение). Проверим на тестовых примерах
Best regards, Буравчик
Re[4]: Поиск подпоследовательностей.
От: bnk СССР http://unmanagedvisio.com/
Дата: 27.05.24 23:10
Оценка:
Здравствуйте, Буравчик, Вы писали:

bnk>>Чат GPT говорит что знает решение за O(N)


Б>Давай его сюда (решение). Проверим на тестовых примерах


https://chatgpt.com/share/6d2d967c-1bf6-4e25-8b96-4dbff67f1629

Вбил просто ради интереса. В суть не вникал. Похоже, что задача с leetcode или типа того.
Re[2]: Поиск подпоследовательностей.
От: steep8  
Дата: 28.05.24 04:45
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>O(N^2) достаточно эффективный? Быстрее что-то не придумывается (если вообще возможно).


O(N^2) неэффективный
Re[5]: Поиск подпоследовательностей.
От: kov_serg Россия  
Дата: 28.05.24 06:07
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>>>Чат GPT говорит что знает решение за O(N)


Б>>Давай его сюда (решение). Проверим на тестовых примерах


bnk>https://chatgpt.com/share/6d2d967c-1bf6-4e25-8b96-4dbff67f1629


По каналу связи передаётся последовательность целых неотрицательных чисел – показания прибора, полученные с интервалом в 1 мин. в течение T мин. (T – целое число). Прибор измеряет количество атмосферных осадков, полученное регистратором за минуту, предшествующую моменту регистрации, и передаёт это значение в условных единицах измерения.

Ученые анализируют последовательность и выявляют смежные диапазоны времени, содержащие не менее K измерений каждый, в которые выпало одинаковое количество осадков.

Определите, сколько таких смежных пар диапазонов есть в снятой последовательности.

в первой строке содержит натуральное число K – минимальное количество показаний в каждом из смежных диапазонов, а во второй – количество переданных показаний N (1 ≤ N ≤ 10 000, N >> K). В каждой из следующих N строк находится одно целое неотрицательное число, не превышающее 1000, обозначающее количество осадков за соответствующую минуту.

Пример данных:
2
8
1
2
3
4
1
1
2
5
При таких исходных данных количество смежных периодов с одинаковым количеством осадков 4: ((2, 3), (4, 1)), ((1, 2, 3), (4, 1, 1)), ((3, 4, 1), (1, 2, 5)), ((2, 3, 4), (1, 1, 2, 5)).

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

ChatGPT

Чтобы эффективно решить эту задачу, можно воспользоваться идеей использования префиксных сумм и хэш-таблиц. Рассмотрим подход, который позволит находить смежные диапазоны времени с одинаковым количеством осадков за время O(N).
Алгоритм:

    Создадим префиксный массив, где каждый элемент будет содержать сумму всех значений осадков от начала до текущего момента.
    Используем хэш-таблицу для хранения индексов предыдущих вхождений суммы осадков.
    Пройдём по массиву показаний осадков и будем проверять наличие смежных диапазонов с одинаковыми значениями сумм осадков.

Шаги реализации:

    Считаем входные данные и инициализируем префиксный массив и хэш-таблицу.
    Заполним префиксный массив, считая суммы осадков от начала до текущего момента.
    Пройдём по префиксному массиву и будем проверять наличие смежных диапазонов, соответствующих условиям задачи.
    Для каждого элемента префиксного массива будем проверять наличие в хэш-таблице записи с таким же значением. Если такие записи найдены, проверим, что их количество удовлетворяет условию минимальной длины K.

Пример кода на Python:


def find_adjacent_ranges_with_equal_precipitation(K, N, precipitations):
    # Префиксная сумма и хэш-таблица
    prefix_sum = [0] * (N + 1)
    sum_indices = {}
    
    # Построение префиксного массива
    for i in range(1, N + 1):
        prefix_sum[i] = prefix_sum[i - 1] + precipitations[i - 1]

    # Проход по префиксному массиву и нахождение смежных диапазонов
    count_ranges = 0
    for i in range(N + 1):
        if prefix_sum[i] in sum_indices:
            for idx in sum_indices[prefix_sum[i]]:
                if i - idx >= K:
                    count_ranges += 1
            sum_indices[prefix_sum[i]].append(i)
        else:
            sum_indices[prefix_sum[i]] = [i]
    
    return count_ranges


# Пример использования
K = 2
N = 8
precipitations = [1, 2, 3, 4, 1, 1, 2, 5]
print(find_adjacent_ranges_with_equal_precipitation(K, N, precipitations))  # Output: 4

Объяснение:

    Префиксный массив prefix_sum строится так, чтобы каждый элемент содержал сумму всех предыдущих значений осадков до текущего индекса.
    Хэш-таблица sum_indices хранит список индексов для каждой встречающейся суммы.
    В основном цикле проверяется, есть ли текущая сумма в хэш-таблице. Если есть, проверяется условие на минимальную длину K, и если оно выполняется, увеличивается счётчик подходящих диапазонов.

Такой подход обеспечивает эффективность и корректность решения задачи.
какая эффективность этого решения
ChatGPT

Эффективность предложенного решения можно оценить следующим образом:

    Построение префиксного массива: Это делается за один проход по массиву осадков, что занимает O(N) времени.
    Проход по префиксному массиву и работа с хэш-таблицей: Каждый элемент префиксного массива проверяется и добавляется в хэш-таблицу, что занимает O(N) времени. В худшем случае для каждого элемента префиксного массива нужно выполнить проверку всех предыдущих индексов с одинаковой суммой, что может занять O(N) в худшем случае. Однако, в среднем случае, доступ и вставка в хэш-таблицу занимают O(1) времени.

Таким образом, общий временной анализ алгоритма:

    Построение префиксного массива: O(N)
    Проход по префиксному массиву и работа с хэш-таблицей: O(N) в среднем случае, O(N^2) в худшем случае

Оценка памяти

    Префиксный массив: O(N)
    Хэш-таблица: O(N) в среднем случае, поскольку она хранит индексы для каждого уникального значения суммы.

Общая сложность

    Временная сложность: O(N) в среднем случае, O(N^2) в худшем случае.
    Пространственная сложность: O(N)

Пример улучшения

Если вы хотите оптимизировать алгоритм для худшего случая, когда много одинаковых значений осадков, можно воспользоваться двунаправленным поиском и бинарным поиском для уменьшения количества проверок. Но в данном контексте предложенный алгоритм с хэш-таблицей уже достаточно эффективен для большинства практических случаев.
а можно 100% улучшить чтобы не было N2
ChatGPT

Да, алгоритм можно улучшить, чтобы избежать временной сложности O(N^2) в худшем случае. Для этого мы будем использовать два указателя (двунаправленный подход) и подсчёт числа последовательных диапазонов одинаковой длины K с использованием хэш-таблицы для хранения индексов.

Вот улучшенный алгоритм, который гарантированно работает за O(N):

    Создаём префиксный массив, чтобы хранить сумму осадков до текущего момента.
    Используем хэш-таблицу для хранения списка индексов, где каждая сумма встречается в префиксном массиве.
    Проходим по массиву осадков и для каждого элемента используем хэш-таблицу для нахождения всех предыдущих индексов с той же суммой.

Этот подход гарантирует линейную сложность O(N) за счёт того, что добавление и поиск в хэш-таблице выполняются за O(1) в среднем случае.
Реализация:


def find_adjacent_ranges_with_equal_precipitation(K, N, precipitations):
    # Префиксная сумма и хэш-таблица
    prefix_sum = [0] * (N + 1)
    sum_indices = {}

    # Построение префиксного массива
    for i in range(1, N + 1):
        prefix_sum[i] = prefix_sum[i - 1] + precipitations[i - 1]

    # Проход по префиксному массиву и нахождение смежных диапазонов
    count_ranges = 0
    for i in range(N + 1):
        current_sum = prefix_sum[i]
        
        if current_sum in sum_indices:
            indices = sum_indices[current_sum]
            # Смотрим только те индексы, которые удовлетворяют условию K
            for idx in indices:
                if i - idx >= K:
                    count_ranges += 1
            sum_indices[current_sum].append(i)
        else:
            sum_indices[current_sum] = [i]

    return count_ranges


# Пример использования
K = 2
N = 8
precipitations = [1, 2, 3, 4, 1, 1, 2, 5]
print(find_adjacent_ranges_with_equal_precipitation(K, N, precipitations))  # Output: 4

Объяснение:

    Построение префиксного массива: O(N)
    Проход по префиксному массиву и работа с хэш-таблицей: O(N)

    В хэш-таблице sum_indices для каждой суммы храним список индексов, где эта сумма встречается.
    Для каждого элемента в префиксном массиве мы проверяем наличие одинаковых сумм в хэш-таблице и проверяем условие минимальной длины K.
    Добавление в хэш-таблицу и поиск в ней выполняются за O(1) в среднем случае, что обеспечивает общую линейную временную сложность.

Таким образом, алгоритм гарантированно работает за O(N) и использует O(N) памяти для хранения префиксного массива и хэш-таблицы.
И как должен выглядеть результат для [1,1,1,1,1,1,1,1,1,1,1,1] ?
ChatGPT

Для последовательности [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] с K = 2 и N = 12 результат должен быть следующим:
Объяснение:

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

Пример:

    (1, 1), (1, 1) — две последовательности длиной 2 с одинаковыми суммами.
    (1, 1, 1), (1, 1, 1) — две последовательности длиной 3 с одинаковыми суммами.
    и так далее.

Подсчёт

Так как K = 2, мы ищем пары смежных диапазонов с длиной от 2 до 12:

    Для длины 2: есть 11 пар диапазонов.
    Для длины 3: есть 10 пар диапазонов.
    ...
    Для длины 11: есть 2 пары диапазонов.
    Для длины 12: есть 1 пара диапазонов.

Суммируем все возможные пары:
11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 66.
Реализация

Убедимся, что наш алгоритм правильно считает для этого примера:


def find_adjacent_ranges_with_equal_precipitation(K, N, precipitations):
    # Префиксная сумма и хэш-таблица
    prefix_sum = [0] * (N + 1)
    sum_indices = {}

    # Построение префиксного массива
    for i in range(1, N + 1):
        prefix_sum[i] = prefix_sum[i - 1] + precipitations[i - 1]

    # Проход по префиксному массиву и нахождение смежных диапазонов
    count_ranges = 0
    for i in range(N + 1):
        current_sum = prefix_sum[i]
        
        if current_sum in sum_indices:
            indices = sum_indices[current_sum]
            # Смотрим только те индексы, которые удовлетворяют условию K
            for idx in indices:
                if i - idx >= K:
                    count_ranges += 1
            sum_indices[current_sum].append(i)
        else:
            sum_indices[current_sum] = [i]

    return count_ranges

# Пример использования
K = 2
N = 12
precipitations = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
print(find_adjacent_ranges_with_equal_precipitation(K, N, precipitations))  # Output: 66

Проверка

Для последовательности [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] с K = 2 и N = 12 алгоритм выдаёт правильный результат 66, что подтверждает его корректность и эффективность.


Для длины 12: есть 1 пара диапазонов. Диапазоны могут пересекаться? — нет, не могут.
sum_indices={}
...
if current_sum in sum_indices

sum_indices содержит предыдущие current_sum, которые всегда меньше чем текущая current_sum (в виду положительности precipitations). Что приводит к отмиранию положительной ветки if алгоритма.
Что подтверждает его корректность и эффективность.
Отредактировано 28.05.2024 6:22 kov_serg . Предыдущая версия .
Re[5]: Поиск подпоследовательностей.
От: Буравчик Россия  
Дата: 28.05.24 06:20
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>https://chatgpt.com/share/6d2d967c-1bf6-4e25-8b96-4dbff67f1629

bnk>Вбил просто ради интереса. В суть не вникал. Похоже, что задача с leetcode или типа того.

Спасибо, интересно. Посмотрел внимательнее.

Решение не рабочее
— Оно всегда возвращает 0 (точнее, если все значения исходного массива ненулевые)
— Оба варианта имеют сложность O(N) — опять же для ненулевых значений
— И вообще решает другую задачу

Объяснение про массив единиц тоже неверное — правильный ответ там 25.
"Для длины 2: есть 11 пар диапазонов" — на самом деле их 9, а не 11. Ну и далее аналогичная ошибка.
Best regards, Буравчик
Re[2]: Поиск подпоследовательностей.
От: Буравчик Россия  
Дата: 28.05.24 06:32
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>O(N^2) достаточно эффективный? Быстрее что-то не придумывается (если вообще возможно).


Оставлю его здесь, раз написал
# решение
def find_adjacent_equal_ranges_count(arr: List[int], k: int) -> int:
    assert k > 0
    result = 0

    # i - точка смежности (первый индекс правого блока)
    for i in range(len(arr)):
        mp_counts = defaultdict(int)

        # считаем возможные суммы вправо от точки смежности, складываем в мапу
        s = 0
        for j in range(i, len(arr)):
            s += arr[j]
            if j - i + 1 >= k:
                mp_counts[s] += 1

        # считаем возможные суммы влево от точки смежности, проверяем наличие в мапе
        s = 0
        for j in reversed(range(0, i)):
            s += arr[j]
            if i - j >= k:
                result += mp_counts.get(s, 0)

    return result

# чтение файла
def read_data(filename: str) -> Tuple[List[int], int]:
    with open(filename, 'r') as fp:
        k = int(fp.readline())
        n = int(fp.readline())
        arr = [int(fp.readline()) for _ in range(n)]
    return arr, k


Сложность по времени O(N^2), по памяти O(N)
Best regards, Буравчик
Re: Поиск подпоследовательностей.
От: Буравчик Россия  
Дата: 29.05.24 07:10
Оценка:
Здравствуйте, steep8, Вы писали:

S>Определите, сколько таких смежных пар диапазонов есть в снятой последовательности.


Это какой-то пробник ЕГЭ 2024? Трудноватая задача для ЕГЭ, не?
Best regards, Буравчик
Re: Поиск подпоследовательностей.
От: Кодт Россия  
Дата: 03.06.24 22:55
Оценка:
Здравствуйте, steep8, Вы писали:

S>Определите, сколько таких смежных пар диапазонов есть в снятой последовательности.


То есть, нужно найти все тройки i<j<k такие что sum(x[i:j]) == sum(x[j:k])

Пусть мы посчитали бегущие суммы: s[i] = sum(x[0:i])

(Отметим, кстати, что если все x неотрицательные (осадки же), то s монотонно растут).

Значит, надо найти s[j]-s[i] == s[k]-s[j]

Штош, тупой алгоритм:
— бежим по i = 0...n-3 включительно
— бежим по j = i+1...n-2
— ищем бисекцией k в j+1...n-1 включительно, такое, что s[k] == s[i]-2*s[j]

и улучшаем его:
— с учётом того, что j растёт, то и s[k] растёт, поэтому на следующей итерации надо начинать бисекцию не с j'+1, а с k
— по этой же причине, j можно инкрементеровать не на 1, а также бисекцией с s[j] == (s[i]+s[k+1])/2
— ну и если k вылетел за границу, то останавливать забег по j
— ну и забег по i тоже останавливается на s[i]*2 > s[n-1]

поэтому забег получается чуть быстрее, чем квадратный (хотя и квадратный в плохом случае)

Надо подумать, можно ли быстрее в принципе...
Перекуём баги на фичи!
Re[2]: Поиск подпоследовательностей.
От: Буравчик Россия  
Дата: 04.06.24 06:08
Оценка: +1
Здравствуйте, Кодт, Вы писали:

К>Штош, тупой алгоритм:

К>и улучшаем его:

Разве здесь не получается O(N^2 * log N) за счет дополнительной бисекции? Вместо обычного квадрата
Best regards, Буравчик
Re[3]: Поиск подпоследовательностей.
От: Кодт Россия  
Дата: 04.06.24 10:02
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Разве здесь не получается O(N^2 * log N) за счет дополнительной бисекции? Вместо обычного квадрата


Э... а получается ли там "обычный квадрат", а не куб?


Хотя, вот если пойти с другого края.
Бежим по j.
Для каждого j бежим по i влево и k вправо.
Да, просто квадрат получается.
Перекуём баги на фичи!
Re[4]: Поиск подпоследовательностей.
От: Буравчик Россия  
Дата: 04.06.24 12:05
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Хотя, вот если пойти с другого края.

К>Бежим по j.
К>Для каждого j бежим по i влево и k вправо.
К>Да, просто квадрат получается.

Да, ровно такой квадратный алгоритм я и привел выше.
Не очень верю, что можно быстрее
Best regards, Буравчик
Re[5]: Поиск подпоследовательностей.
От: Кодт Россия  
Дата: 10.06.24 18:49
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Да, ровно такой квадратный алгоритм я и привел выше.

Б>Не очень верю, что можно быстрее

Допустим, мы не только построили бегущие суммы s[i], но и словарь индексов для них.
Тогда для каждого (i,j) мы будем искать sk == sj*2-si, то есть, проверять вхождение k в словарь.
Пока что всё ещё квадрат — тупо потому, что бегаем по двум индексам.
Ничего лучшего из этой мемоизации не выжать.
В вырожденных случаях — например, массив "все нули" или "все единицы" даёт сочетания всех-со-всеми — у нас ответ имеет порядок n^2, а поскольку мы формируем его из независимого подсчёта "разов", то мы должны встретить эти "разы" квадрат раз и сделать квадрат инкрементов.
Значит, если и искать решение, — то только в сторону каких-то оптимизаций, "если на таком-то отрезке у нас ответ M, то на этаком-то — M+L"
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.