Коллекции

Цикл статей который стоит прочитать - https://habr.com/en/post/319164/ .

Замечания к статьям:

Большинство объектов в питоне просто лежат в оперативной памяти, а каждая переменная представляет из себя ссылку на участок оперативной памяти где он лежит. Это может привести к проблемам, если вы сошлетесь на один и тот же изменяемый объект разными переменными.

a = [1, 2, 3, 4]
b = a

Обе переменные указывают на один и тот же участок в памяти, поэтому если мы теперь обратимся к объекту в переменной b и изменим его, то изменится и тотже объект, на который ссылается переменная a .

a = [1, 2, 3, 4]
b = a
b[2] = "Oh shit"
print(a)  # [1, 2, "Oh shit", 4]

Возможно это очевидно, но на всякий случай. Если мы сделаем

a = [1, 2, 3, 4]
b = a
b = [2, 3, 4]

Это переприсваивание b никак не скажется на списке a, так как в этом случае мы просто говорим переменной b смотреть на дргуой список в памяти, а не обращаемся к объекту, на который указывает b и меняем его.

Изменять объект на который указывает переменная можно только через методы этого объекта или обращаясь напрямую к его аттрибутам. Присвоение чего-то в переменную просто заставляет переменную указывать на другой место в памяти.

Как копировать списки, описано в статье. Ссылки на информацию про Big O notation там есть.

Вот на русском простенькая статья есть, но слишком поверхностная. К тому же вставка в список в основном занимает не O(n), а O(1), если это вставка в конец списка.

Сколько стоят операции над list, set и dict в Python? Разбираемся с временной сложностью

Циклы

В питоне два типа циклов while и for , первый такой же как и в большинстве распространенных языков.

Про цикл while можно почитать в документации питона/на любом сайте, там все очень просто.