Задачи на слайсы
1) Что выведет данная программа и почему?
package main
import ("fmt")
func main() {
arr1 :=[...]int{1, 2,3, 4, 5}
arr2 := arr1[:4]
arr3 := append(arr2[:2], 9, 8, 7)
fmt.Println(arr3)
fmt.Println(arr2)
fmt.Println(arr1)
}Программа выведет следующие значения:
[1 2 9 8 7]
[1 2 9 8]
[1 2 9 8 7]Давайте разберемся, почему так происходит:
arr1 := [...]int{1, 2, 3, 4, 5}создает массивarr1с пятью элементами.arr2 := arr1[:4]создает срезarr2, который ссылается на первые четыре элемента массиваarr1. То естьarr2это[1, 2, 3, 4].arr3 := append(arr2[:2], 9, 8, 7)берет срез первых двух элементов изarr2(то есть[1, 2]), и добавляет к нему элементы9, 8, 7. Важно отметить, чтоappendможет изменять исходный массив, если в нем достаточно места для новых элементов.В данном случае, начало слайса
arr2ссылается на начало массиваarr1, поэтому изменения вarr2отражаются наarr1.После выполнения
append,arr3становится[1, 2, 9, 8, 7],arr2изменяется на[1, 2, 9, 8], (7ка не влазит, так как слайсarr2имеет фиксированную длину в 4 элемента), аarr1теперь[1, 2, 9, 8, 7] (так как в нем достаточно места и для 7ки).Вывод
fmt.Println(arr3),fmt.Println(arr2),fmt.Println(arr1)показывает измененные значения массивов и срезов после операций сappend.
Это пример того, как операции с срезами и функцией append могут влиять на исходные массивы в Go, особенно когда срезы создаются на основе этих массивов.
2) Что выведет данная программа и почему?
3) Что будет выведено без аппенд и потом с ним?
Давайте разберем, что произойдет в коде с и без использования append.
Код без использования append
appendОбъяснение:
В функции
mainсоздается срезslс элементами[1, 2, 3, 4].Срез
slпередается в функциюmod.В функции
modпроисходит итерация по срезуa(который является ссылкой наsl), и каждый элемент заменяется на5.После выполнения функции
mod, срезslвmainбудет изменен на[5, 5, 5, 5], так как срезы в Go передаются по ссылке.
Вывод:
Код с использованием append
appendОбъяснение:
В функции
mainсоздается срезslс элементами[1, 2, 3, 4].Срез
slпередается в функциюmod.В функции
modвыполняетсяappend(a, 125), что создает новый срез, который является копиейaс добавленным элементом125. Этот новый срез присваивается переменнойaвнутри функцииmod.Затем происходит итерация по новому срезу
a, и каждый элемент заменяется на5. Однако это изменение не влияет на исходный срезsl, так какaтеперь указывает на новый срез.После выполнения функции
mod, срезslвmainостанется неизменным, так как изменения были сделаны в копии среза.
Вывод:
Заключение
Без использования
append: Срезslбудет изменен на[5, 5, 5, 5], так как изменения происходят непосредственно в переданном срезе.С использованием
append: Срезslостанется неизменным[1, 2, 3, 4], так какappendсоздает новый срез, и изменения происходят в этом новом срезе, а не в исходном.
4) Написать функцию, которая на вход принимает 2 отсортированных слайса с типом Int в ответ выдает 1 отсортированный слайс, содержащий данные из входящих слайсов. Оценить сложность алгоритма.
Для объединения двух отсортированных слайсов в один отсортированный слайс можно использовать алгоритм слияния, который является частью алгоритма сортировки слиянием (merge sort). Этот алгоритм работает за линейное время, то есть его временная сложность составляет O(n + m), где n и m — размеры входных слайсов.
Реализация функции на Go
Объяснение алгоритма
Инициализация:
Создаем результирующий слайс
resultс начальной емкостью, равной сумме длин входных слайсовaиb.Инициализируем индексы
iиjдля итерации по слайсамaиbсоответственно.
Основной цикл слияния:
Пока оба индекса
iиjнаходятся в пределах длин своих слайсов, сравниваем текущие элементыa[i]иb[j].Добавляем меньший элемент в результирующий слайс и увеличиваем соответствующий индекс.
Добавление оставшихся элементов:
После завершения основного цикла, один из слайсов может содержать оставшиеся элементы. Добавляем их в результирующий слайс.
Оценка сложности
Временная сложность: O(n + m), где n и m — размеры входных слайсов. Это обусловлено тем, что каждый элемент из обоих слайсов обрабатывается ровно один раз.
Пространственная сложность: O(n + m), так как создается новый слайс, содержащий все элементы из входных слайсов.
Этот алгоритм является оптимальным для задачи слияния двух отсортированных слайсов и работает эффективно даже для больших входных данных.
5) Что выведет данная программа и почему?
Давайте разберем, что происходит в этой программе и что она выведет.
Разбор кода
Создание и заполнение слайса
x:После этих операций
xбудет содержать[0, 1, 2].Создание слайсов
yиz:Здесь начинается интересное. Важно понимать, что
appendможет изменять базовый массив слайса, если его емкость позволяет. Если емкость недостаточна,appendсоздаст новый массив и скопирует в него данные.y := append(x, 3)добавляет3кx, так чтоyстановится[0, 1, 2, 3].z := append(x, 4)добавляет4кx, так чтоzстановится[0, 1, 2, 4].
Однако, так как
xиyссылаются на один и тот же базовый массив, изменениеxчерезappendможет повлиять наy.
Вывод программы
Когда мы вызываем fmt.Println(y, z), мы получаем:
Почему так происходит?
Когда
y := append(x, 3)выполняется,yссылается на тот же базовый массив, что иx, но с дополнительным элементом3.Когда
z := append(x, 4)выполняется,zтакже ссылается на тот же базовый массив, что иx, но с дополнительным элементом4.
Так как x и y ссылаются на один и тот же базовый массив, изменение x через append влияет на y. В результате, оба слайса y и z содержат [0, 1, 2, 4].
Заключение
Программа выводит [0 1 2 4] [0 1 2 4] из-за того, что append изменяет базовый массив слайса, если его емкость позволяет. В данном случае, x, y и z ссылаются на один и тот же базовый массив, что приводит к такому результату.
6) Задача: Требуется реализовать функцию uniqRandn, которая генерирует слайс длины n уникальных рандомных чисел:
Для реализации функции uniqRandn, которая генерирует слайс длины n уникальных случайных чисел, можно использовать несколько подходов. Один из них — это использование карты (map) для отслеживания уже сгенерированных чисел, чтобы избежать дубликатов.
Реализация функции uniqRandn
uniqRandnИмпорт необходимых пакетов:
math/randдля генерации случайных чисел.timeдля инициализации генератора случайных чисел.
Инициализация генератора случайных чисел:
Используем текущее время в наносекундах для инициализации генератора случайных чисел.
Использование карты для отслеживания уникальных чисел:
Генерируем случайные числа и добавляем их в карту до тех пор, пока не наберем нужное количество уникальных чисел.
Код
Объяснение кода
Инициализация генератора случайных чисел:
Это гарантирует, что генератор случайных чисел будет инициализирован текущим временем, что делает последовательность случайных чисел уникальной при каждом запуске программы.
Создание карты и слайса:
Карта
numsиспользуется для отслеживания уникальных чисел, а слайсresultдля хранения результата.Генерация уникальных случайных чисел:
Цикл продолжается до тех пор, пока количество уникальных чисел в карте
numsне достигнетn. Внутри цикла генерируется случайное числоnum. Если это число еще не присутствует в картеnums, оно добавляется в карту и слайсresult.
Заключение
Этот код генерирует слайс длины n уникальных случайных чисел. Если требуется другой диапазон случайных чисел, можно изменить аргумент функции rand.Intn. Например, для генерации чисел в диапазоне от 0 до 999, используйте rand.Intn(1000).
Last updated