Add dedicated chapter exercise sections and generated exercise pages for the English, Japanese, and Russian editions. Add navigation for all published languages while keeping Taiwan Traditional Chinese exercise pages generated at build time.
8.8 KiB
Упражнения
Вопросы для самопроверки
Как массив и связный список находят элемент
В массиве и односвязном списке по порядку хранятся [A, B, C, D, E]. Требуется прочитать 4-й элемент D.
- Какой индекс можно напрямую использовать в массиве?
- Через какие узлы нужно последовательно пройти по
nextв односвязном списке, начиная с головного узлаA? - Как меняется число шагов в каждой структуре по мере удаления нужного элемента от начала? Какая структура лучше подходит для многократного доступа по позиции и почему?
??? success "Ответ"
1. Если индексация начинается с 0, индекс 4-го элемента равен 3, поэтому в массиве можно напрямую обратиться к `arr[3]`.
2. В односвязном списке нужно начинать с головы. Путь имеет вид `A → B → C → D`, то есть по `next` нужно перейти 3 раза.
3. Массив позволяет напрямую определить положение элемента по адресу начала и индексу, поэтому временная сложность доступа по позиции равна $O(1)$.
Чтобы обратиться к $k$-му узлу односвязного списка, нужно начать с головного узла и перейти по `next` $k-1$ раз,
что в худшем случае требует $O(n)$ времени.
Здесь сравнивается только доступ по позиции; это не означает, что связный список медленнее при всех операциях.
Как вставить элемент в массив и связный список
В массиве и односвязном списке хранятся A, B, C, D. Требуется вставить X после B.
- емкость массива равна 5, его текущее состояние —
[A, B, C, D, _]; - связный список имеет вид
A → B → C → D, и ссылка на узелBуже получена.
- Какие элементы массива нужно переместить? Запишите массив после вставки.
- В каком порядке следует изменить
X.nextиB.next? Запишите связный список после вставки. - Почему при сравнении эффективности вставки важно уточнить, что «ссылка на узел B уже получена»?
??? success "Ответ"
1. В массиве сначала нужно сдвинуть `D` на одну позицию вправо, затем так же сдвинуть `C` и, наконец, поместить `X` по индексу 2.
Получится `[A, B, X, C, D]`.
2. Изначально `B.next` указывает на `C`. Сначала следует выполнить `X.next = B.next`, чтобы `X` указывал на `C`,
а затем `B.next = X`. Получится `A → B → X → C → D`.
Если сначала перезаписать `B.next`, не сохранив прежнюю связь, узел `C` можно потерять.
3. Если положение `B` известно, для вставки в связный список достаточно изменить две связи, что занимает $O(1)$ времени.
Если же `B` еще нужно искать от головы списка, сам поиск может потребовать $O(n)$ времени.
Как растет емкость списка
Список на основе массива сейчас содержит [A, B, C], его длина size = 3, а емкость capacity = 4.
При нехватке места емкость нового массива увеличивается в 2 раза.
- Чему будут равны длина и емкость списка после добавления
D? Потребуется ли увеличить емкость? - Затем добавляют
E. Какой станет емкость и сколько прежних элементов потребуется скопировать? - Длина базового массива неизменна. Почему тогда кажется, что емкость списка может расти?
??? success "Ответ"
1. `D` можно поместить в последнюю свободную ячейку. Теперь содержимое равно `[A, B, C, D]`,
`size = 4`, `capacity = 4`, и увеличивать емкость не требуется.
2. Для `E` свободного места уже нет, поэтому нужно создать новый массив емкостью 8,
скопировать в него 4 прежних элемента `A, B, C, D`, а затем добавить `E`.
После этого `size = 5`, `capacity = 8`.
3. Исходный массив сам по себе не удлиняется. Список создает новый массив большего размера, копирует прежние элементы
и затем использует новый массив как базовое хранилище. Поэтому для пользователя емкость выглядит увеличившейся.
Задачи по программированию
Прибавление единицы к большому числу в массиве
Массив digits хранит слева направо цифры неотрицательного целого числа. Например, [3, 0, 8] обозначает 308.
Число 0 представлено как [0]; у всех остальных входных данных первая цифра не равна 0.
Смоделируйте сложение столбиком в десятичной системе: увеличьте это число на 1 и верните результат в том же формате массива.
Массив digits можно изменять непосредственно. Если перед первой цифрой появляется новый перенос, можно вернуть более длинный массив.
??? tip "Подсказки"
1. Как при сложении столбиком, начните с последней цифры массива
2. Если текущая цифра меньше 9, увеличьте ее на один и сразу верните результат
3. Если текущая цифра равна 9, замените ее на 0; если все цифры равны 9, добавьте 1 в начало
LeetCode{ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" }
Разворот односвязного списка
Дан головной узел head односвязного списка. Каждый узел содержит значение и поле next, указывающее на следующий узел.
Итеративно разверните все связи между узлами и верните новый головной узел. Не создавайте новые узлы связного списка.
??? tip "Подсказки"
1. Нарисуйте на бумаге три связанных узла и два указателя prev и cur
2. Прежде чем изменить cur.next, сохраните исходный следующий узел в nxt
3. Развернув cur.next, выполните prev = cur, затем cur = nxt и продолжайте с очередным узлом исходного списка
LeetCode{ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" }