Max Consecutive Ones
Тебе дан массив nums, в котором каждое значение — 0 или 1. Серия — это последовательность единиц, расположенных подряд, без 0 между ними. Верни длину самой длинной серии или 0, если в массиве нет ни одной единицы.
Функция
- numsinteger-array
- массив из 0 и 1
- Возвращаетinteger
- длина самой длинной последовательности подряд идущих единиц
Ограничения
1 ≤ nums.length ≤ 2 × 104- Каждый
nums[i]равен0или1.
Примеры
- Ввод
- nums = [1, 1, 0, 1, 1, 1, 0, 1]
- Вывод
- 3
- Пояснение
- Единицы образуют три серии: индексы
0–1(длина 2),3–5(длина 3) и индекс7отдельно (длина 1). Самая длинная имеет длину3.
- Ввод
- nums = [0, 1, 0, 1, 1]
- Вывод
- 2
- Пояснение
- Одиночная
1с индексом1уступает паре с индексами3и4, поэтому ответ —2.
- Ввод
- nums = [0, 0, 0]
- Вывод
- 0
- Пояснение
- Единицы нигде нет, поэтому нет и серии, а ответ —
0.
Дополнительный вопрос
Что, если можно перевернуть не более k нулей в единицы? Какой длины может стать самая длинная последовательность и можно ли найти её за один проход?
Подсказки
Открывайте по одной. Каждая подсказывает чуть больше.
Последовательность единиц заканчивается, как только появляется
0. Что тебе нужно помнить о значениях, которые ты уже прошёл?Важна только длина последовательности, заканчивающейся на текущем индексе. 1 увеличивает её на единицу, а 0 сбрасывает её до нуля.
Пройди по массиву один раз, используя два числа: длину текущей серии и лучшую длину на данный момент. После каждой 1 увеличивай длину текущей серии и сравнивай её с лучшей; после каждой 0 сбрасывай длину текущей серии.
Решение
Последовательность завершается в тот момент, когда появляется 0, поэтому для каждого индекса нужно знать только длину последовательности, заканчивающейся на нём. Один счётчик, который увеличивается при 1 и сбрасывается при 0, находит самую длинную последовательность за один проход.
Считайте вперёд от каждого индекса
Верно, но не успевает на самых больших тестах
Идея
Попробуй начать с каждого индекса и двигайся вперёд, пока встречаются единицы; число шагов — это длина последовательности, начинающейся с этого индекса. Самая длинная последовательность начинается с одного из этих индексов, поэтому ответ — наибольшее количество.
Эти проходы пересекаются. Для массива из n единиц они занимают примерно n² / 2 шагов, то есть 2 × 10^8 при n = 2 × 10^4.
Алгоритм
- Установите
best = 0. - Для каждого индекса
startустановитеlength = 0. - Пока
start + lengthнаходится внутри массива иnums[start + length]равно1, увеличивайтеlengthна 1. - Оставьте большее из значений
bestиlength. - Верните
best.
def findMaxConsecutiveOnes(nums):
n = len(nums)
best = 0
for start in range(n):
length = 0
while start + length < n and nums[start + length] == 1:
length += 1
best = max(best, length)
return bestОдин проход с текущим счётчиком
Идея
Храни current — длину последовательности единиц, которая заканчивается на текущем индексе. Единица увеличивает эту последовательность на один элемент; ноль завершает её, поэтому current становится равным 0. Длина каждой последовательности измеряется на её последнем индексе, где current равна её полной длине, поэтому наибольшее значение, которого достигает current, и есть ответ.
Для [1, 1, 0, 1, 1, 1, 0, 1] значения current равны 1, 2, 0, 1, 2, 3, 0, 1, а наибольшее значение — 3.
Алгоритм
- Установите
best = 0иcurrent = 0. - Для каждого значения в
nums: если оно равно1, прибавьте 1 кcurrentи сохраните большее из значенийbestиcurrent. - Если оно равно
0, установитеcurrent = 0. - Верните
best.
def findMaxConsecutiveOnes(nums):
best = 0
current = 0
for x in nums:
if x == 1:
current += 1
best = max(best, current)
else:
# A 0 breaks the run.
current = 0
return best
Ловушки и крайние случаи
- Обновлять
bestтолько при встрече с0. Серия, которая доходит до конца, как в[0, 1, 1], никогда не записывается. Обновляйте после каждой1или выполняйте ещё одно сравнение после цикла. - Не сбрасывать
currentпри встрече с0. Отдельные серии складываются, и[1, 1, 0, 1, 1]возвращает4. - Задавать начальное значение
bestравным1илиnums[0]. Для[0, 0, 0]должно возвращаться0. - В Lua и R, где индексация массивов начинается с 1, ограничивать проход вперёд условием
< nвместо≤ n. Последнее значение никогда не считывается, поэтому[0, 1]возвращает0.
Частые вопросы3
Какова временная сложность задачи «Максимальное количество последовательных единиц»?
Решение за один проход работает за время O(n), потому что оно считывает каждое значение один раз, и использует O(1) дополнительной памяти: один счётчик для текущей последовательности и один для наилучшей. Перезапуск подсчёта на каждом индексе занимает O(n²) для массива, состоящего только из 1.
Почему счётчик сбрасывается до 0, а не до 1?
Счётчик хранит длину последовательности, которая заканчивается на текущем индексе. Если значение в этой позиции равно 0, там не заканчивается последовательность из единиц, поэтому её длина равна 0. Следующая единица увеличивает его до 1 — длины новой последовательности.
Является ли задача «Максимальное количество подряд идущих единиц» задачей на скользящее окно?
Можно рассматривать это как одно целое: окно содержит текущую последовательность, его правая граница сдвигается при каждом значении, а 0 перемещает левую границу за него. Окно не сужается шаг за шагом, поэтому один счётчик заменяет две границы.
Похожие задачи
Задачи на те же идеи. Решите две или три, и приём запомнится.
def findMaxConsecutiveOnes(nums):
# Напишите код здесьТест #1
Тест #2
Тест #3
Аргумент
nums = [1, 1, 0, 1, 1, 1, 0, 1]
Ожидаемый вывод
3