Часто в задачах приходится хранить прямоугольные таблицы с данными. Такие таблицы называются матрицами или двумерными массивами. В языке программирования Питон таблицу можно представить в виде списка строк, каждый элемент которого является в свою очередь списком, например, чисел. Например, создать числовую таблицу из двух строк и трех столбцов можно так:
A = [ [1, 2, 3], [4, 5, 6] ]
Здесь первая строка списка A[0]
является списком из чисел
[1, 2, 3]
. То есть A[0][0] == 1
, значение
A[0][1] == 2
, A[0][2] == 3
,
A[1][0] == 4
, A[1][1] == 5
,
A[1][2] == 6
.
Для обработки и вывода списка как правило используется два вложенных цикла. Первый цикл по номеру строки, второй цикл по элементам внутри строки. Например, вывести двумерный числовой список на экран построчно, разделяя числа пробелами внутри одной строки, можно так:
for i in range(len(A)): for j in range(len(A[i]): print(A[i][j], end = ' ') print()
То же самое, но циклы не по индексу, а по значениям списка:
for row in A: for elem in row: print(elem, end = ' ') print()
Естественно для вывода одной строки можно воспользоваться
методом join
:
for row in A: print(' '.join(list(map(str, row))))
Используем два вложенных цикла для подсчета суммы всех чисел в списке:
S = 0 for i in range(len(A)): for j in range(len(A[i])): S += A[i][j]
Или то же самое с циклом не по индексу, а по значениям строк:
S = 0 for row in A: for elem in row: S += elem
Пусть даны два числа: количество строк n
и количество столбцов
m
. Необходимо создать список размером n
×m
, заполненный нулями.
Очевидное решение оказывается неверным:
A = [[0] * m ] * n
В этом легко убедиться, если присвоить элементу A[0][0]
значение 1
, а потом вывести значение другого элемента A[1][0]
— оно тоже будет равно 1! Дело в том, что
[0] * m
возвращает ccылку на список из m
нулей.
Но последующее повторение этого элемента создает список из n
элементов, которые являются ссылкой на один и тот же список (точно
так же, как выполнение операции B = A
для списков не создает
новый список), поэтому все строки результирующего списка на самом деле
являются одной и той же строкой.
Таким образом, двумерный список нельзя создавать при помощи операции повторения одной строки. Что же делать?
Первый способ: сначала создадим список из n
элементов
(для начала просто из n
нулей). Затем сделаем каждый
элемент списка ссылкой на другой одномерный список из m
элементов:
A = [0] * n for i in range(n): A[i] = [0] * m
Другой (но похожий) способ: создать пустой список, потом n
раз добавить в него новый элемент, являющийся списком-строкой:
A = [] for i in range(n): A.append([0] * m)
Но еще проще воспользоваться генератором: создать список из
n
элементов, каждый из которых будет списком,
состоящих из m
нулей:
A = [[0] * m for i in range(n)]
В этом случае каждый элемент создается независимо от остальных
(заново конструируется список [0] * m
для заполнения очередного
элемента списка), а не копируются ссылки на один и тот же список.
Пусть программа получает на вход двумерный массив, в виде
n
строк, каждая из которых содержит m
чисел, разделенных пробелами. Как их считать? Например, так:
A = [] for i in range(n): A.append(list(map(int, input().split())))
Или, без использования сложных вложенных вызовов функций:
A = [] for i in range(n): row = input().split() for i in range(len(row)): row[i] = int(row[i]) A.append(row)
Можно сделать то же самое и при помощи генератора:
A = [list(map(int, input().split())) for i in range(n)]
Пусть дан квадратный массив из n
строк и n
столбцов.
Необходимо элементам, находящимся на главной диагонали, проходящей из левого верхнего угла в правый
нижний (то есть тем элементам A[i][j]
, для которых i == j
)
присвоить значение 1
, элементам,
находящимся выше главной диагонали – значение 0, элементам, находящимся ниже главной диагонали – значение 2. То есть получить такой массив
(пример для n==4
):
1 0 0 0 2 1 0 0 2 2 1 0 2 2 2 1
Рассмотрим несколько способов решения этой задачи. Элементы, которые лежат выше главной диагонали – это элементы
A[i][j]
, для которых i < j
, а для элементов ниже главной диагонали i > j
. Таким образом, мы можем
сравнивать значения i
и j
и по ним определять значение A[i][j]
. Получаем следующий алгоритм:
for i in range(n): for j in range(n): if i < j: A[i][j] = 0 elif i > j: A[i][j] = 2 else: A[i][j] = 1
Данный алгоритм плох, поскольку выполняет одну или две инструкции if
для обработки каждого элемента.
Если мы усложним алгоритм, то мы сможем обойтись вообще без условных инструкций.
Сначала заполним главную диагональ, для чего нам понадобится один цикл:
for i in range(n): A[i][i] = 1
Затем заполним значением 0
все элементы выше главной диагонали, для чего нам понадобится в каждой из строк
с номером i
присвоить значение элементам A[i][j]
для j
=i+1
, ..., n-1
. Здесь нам
понадобятся вложенные циклы:
for i in range(n): for j in range(i + 1, n): A[i][j] = 0
Аналогично присваиваем значение 2
элементам A[i][j]
для j
=0
, ..., i-1
:
for i in range(n): for j in range(0, i): A[i][j] = 2
Можно также внешние циклы объединить в один и получить еще одно, более компактное решение:
for i in range(n): for j in range(0, i): A[i][j] = 2 A[i][i] = 1 for j in range(i + 1, n): A[i][j] = 0
А вот такое решение использует операцию повторения списков для построения очередной
строки списка. i
-я строка списка состоит из i
чисел
2
, затем идет одно число 1
, затем идет n-i-1
число 0
:
for i in range(n): A[i] = [2] * i + [1] + [0] * (n - i - 1)
А можно заменить цикл на генератор:
A = [ [2] * i + [1] + [0] * (n - i - 1) for i in range(n)]
В некоторых заданиях этого листка требуется
выводить элементы списка аккуратными столбцами, выравнивая числа по правому
краю с фиксированной шириной столбца. Это можно сделать разными способами,
один из способов: использование метода rjust
.
rjust
— метод объекта типа str
,
принимающий два параметра: длину новой строки (ширина поля вывода) и символ-заполнитель:
rjust(n, ch)
.
Например, S.rjust(10, '.')
. Метод возвращает новую строку, длина которой
равна n символов, исходная строка находится в конце результата (то есть исходная строка
“выравнивается” по правому краю), лишние позиции заполняются символом ch.
Если опустить ch, то в качестве символа-заполнителя используется пробел. Если длина исходной
строки была больше n, то возвращается исходная строка без изменений (строка не обрезается).
Аналогично есть методы ljust
, выравнивающий строку по левому краю и center
,
выравнивающий строку по центру результата.
Найдите индексы первого вхождения максимального элемента. Выведите два числа: номер строки и номер столбца, в которых стоит наибольший элемент в двумерном массиве. Если таких элементов несколько, то выводится тот, у которого меньше номер строки, а если номера строк равны то тот, у которого меньше номер столбца.
Программа получает на вход размеры массива n
и
m
, затем n
строк по m
чисел в каждой.
Ввод | Вывод |
---|---|
3 4 |
1 2 |
Дано нечетное число n
. Создайте двумерный массив из
n
×n
элементов, заполнив
его символами "."
(каждый элемент массива является
строкой из одного символа). Затем заполните символами "*"
среднюю строку массива, средний столбец массива, главную диагональ
и побочную диагональ. В результате единицы в массиве должны образовывать изображение
звездочки. Выведите полученный массив на экран, разделяя элементы
массива пробелами.
Ввод | Вывод |
---|---|
5 |
* . * . * |
Даны два числа n
и m
. Создайте двумерный массив
размером n×m
и заполните его символами "."
и "*"
в шахматном порядке. В левом верхнем углу должна стоять точка.
Ввод | Вывод |
---|---|
3 4 |
. * . * |
Дано число n
. Создайте массив
размером n×n
и заполните его по следующему правилу. На главной диагонали
должны быть записаны числа 0. На двух диагоналях, прилегающих к главной, числа 1.
На следующих двух диагоналях числа 2, и т.д.
Ввод | Вывод |
---|---|
5 |
0 1 2 3 4 |
Дано число n
. Создайте массив
размером n×n
и заполните его по следующему правилу:
Числа на диагонали, идущей из правого верхнего в левый нижний угол равны 1.
Числа, стоящие выше этой диагонали, равны 0.
Числа, стоящие ниже этой диагонали, равны 2.
Полученный массив выведите на экран. Числа в строке разделяйте одним пробелом.
Ввод | Вывод |
---|---|
4 |
0 0 0 1 |
Дан двумерный массив и два числа: i
и j
.
Поменяйте в массиве столбцы с номерами i
и j
и выведите результат.
Программа получает на вход размеры массива n
и
m
, затем элементы массива, затем числа
i
и j
.
Решение оформите в виде функции SwapColumns(A, i, j)
.
Ввод | Вывод |
---|---|
3 4 |
12 11 13 14 |
Дано число n
и массив размером n×n
.
Проверьте, является ли этот массив симметричным относительно
главной диагонали. Выведите слово “YES
”,
если массив симметричный, и слово “NO
”
в противном случае.
Решение оформите в виде функции IsSymmetric(A)
.
Ввод | Вывод |
---|---|
3 |
YES |
Дан квадратный двумерный массив размером n×n
и число k
. Выведите элементы k
-й по счету
диагонали ниже главной диагонали (т.е. если k == 1
,
то нужно вывести элементы первой диагонали, лежащей ниже главной,
если k == 2
, то второй диагонали и т.д.).
Значение k
может быть отрицательным, например,
если k == -1
, то нужно вывести значение первой
диагонали лежащей выше главной. Если k == 0
,
то нужно вывести элементы главной диагонали.
Программа получает на вход число n
, затем массив
размером n×n
, затем число k
.
Сложность алгоритма вывода (без учета ввода данных) должна быть \(O(n)\), то есть нельзя вывод осуществлять проходом по всему двумерному массиву.
Ввод | Вывод |
---|---|
4 |
5 1 6 |
4 |
3 8 |
Дан двумерный массив размером n×m
.
Симметричный ему относительно главной диагонали массив
называется транспонированным к данному. Он имеет размеры
m×n
: строки исходного массива становятся
столбцами транспонированного, столбцы исходного массива
становятся строками транспонированного.
Для данного массива постройте транспонированный массив
и выведите его на экран. Решение оформите в виде функции
Transpose(A)
.
Ввод | Вывод |
---|---|
3 4 |
11 21 31 |
Дан двумерный массив размером n×n
.
Транспонируйте его и результат запишите в этот же масссив.
Вспомогательный массив использовать нельзя.
Решение оформите в виде функции
Transpose (A)
.
Ввод | Вывод |
---|---|
3 |
1 4 7 |
Дан квадратный массив. Поменяйте местами элементы, стоящие на главной и побочной диагонали, при этом каждый элемент должен остаться в том же столбце (то есть в каждом столбце нужно поменять местами элемент на главной диагонали и на побочной диагонали).
Решение оформите в виде функции
SwapDiagonals(A)
.
Ввод | Вывод |
---|---|
3 |
7 2 9 |
В кинотеатре n рядов по m мест в каждом. В двумерном массиве хранится информация о проданных билетах, число 1 означает, что билет на данное место уже продано, число 0 означает, что место свободно. Поступил запрос на продажу k билетов на соседние места в одном ряду. Определите, можно ли выполнить такой запрос.
Программа получает на вход числа n и m. Далее идет n строк, содержащих m чисел (0 или 1), разделенных пробелами. Затем дано число k.
Программа должна вывести номер ряда, в котором есть k подряд идущих свободных мест. Если таких рядов несколько, то выведите номер наименьшего подходящего ряда. Если подходящего ряда нет, выведите число 0.
Ввод | Вывод |
---|---|
3 4 |
2 |
3 3 |
0 |
Даны два числа n и m. Создайте массив n×m
и заполните его по следующим правилам:
Числа, стоящие в строке 0 или в столбце 0 равны 1
(A[0][j] = 1
, A[i][0] = 1
). Для всех остальных
элементов массива A[i][j] = A[i-1][j] + A[i][j-1]
, то есть
каждый элемент равен сумме двух элементов, стоящих слева и сверху
от него.
Выведите данный массив на экран, отводя на вывод каждого элемента массива ровно 6 символов (см. пример).
Ввод | Вывод |
---|---|
4 6 |
1 1 1 1 1 1 |
Дан одномерный список из \(n\times m\) элементов. Сделайте из него двумерный список из \(n\) строк по \(m\) элементов в каждой.
Программа получает на вход числа \(n\) и \(m\). Во второй строке записано \(nm\) целых чисел через пробел.
Создайте двумерный список из данных чисел и выведите его на экран в виде двумерной таблицы, разделяя элементы одним пробелом.
Ввод | Вывод |
---|---|
2 5 |
0 1 2 3 4 |
На шахматной доске стоит конь. Отметьте положение коня на доске и все клетки, которые бьет конь.
Программа получает на вход координаты коня на шахматной доске в шахматной нотации (то есть в виде “e4”, где сначала записывается номер столбца (буква от “a” до “h”, слева направо), затем номеру строки (цифра от 1 до 8, снизу вверх).
Клетку, где стоит конь, отметьте буквой “K”, клетки, которые бьет конь, отметьте символами “*”, остальные клетки заполните точками.
Выведите на экран изображение доски.
Ввод | Вывод |
---|---|
b6 |
* . * . . . . . |
Как красиво перебирать ходы коня?
MOVES = [[2, 1], [2, -1], [1, 2], [1, -2], [-1, 2], [-1, -2], [-2, 1], [-2, -1]] ... for dx, dy in MOVES: nx, ny = x + dx, y + dy
Решите предыдущую задачу для ферзя. Ферзь обозначается буквой “Q”.
Ввод | Вывод |
---|---|
c4 |
. . * . . . * . |
По данным числам n и m заполните двумерный массив размером n×m числами от 1 до n×m “змейкой”, как показано в примере. Выведите полученный массив, отводя на вывод каждого элемента ровно 4 символа.
Ввод | Вывод |
---|---|
3 5 |
1 2 3 4 5 |
По данным числам n и m заполните двумерный массив размером n×m числами от 1 до n×m “диагоналями”, как показано в примере. Выведите полученный массив, отводя на вывод каждого элемента ровно 4 символа.
Ввод | Вывод |
---|---|
3 5 |
1 2 4 7 10 |
Дан прямоугольный массив размером n×m. Поверните его на 90 градусов по часовой стрелке, записав результат в новый массив размером m×n.
Выведите получившийся массив. Числа при выводе разделяйте одним пробелом.
Ввод | Вывод |
---|---|
3 4 |
31 21 11 |
Дан квадратный массив. Поверните его на 90 градусов по часовой стрелке. Результат запишите в этот же массив, вспомогательный массив использовать нельзя.
Выведите результат на экран, разделяя числа одним пробелом.
Ввод | Вывод |
---|---|
3 |
7 4 1 |
Даны числа n и m. Создайте двумерый массив размером n×m, заполненный нулями.
Затем при помощи одного цикла заполните его таблицей умножения по формуле A[i][j] = i * j
.
При заполнении массива нельзя использовать вложенные циклы.
Генератор списка также считается циклом.
Выведите получившийся массив на экран (при выводе можно использовать вложенные циклы), отводя на вывод каждого числа ровно 4 символа.
То есть программа должна выглядеть примерно так:
n, m = map(int, input().split()) A = ... for i in range(n * m): ... # Вывод списка A
Ввод | Вывод |
---|---|
4 6 |
0 0 0 0 0 0 |
Даны числа n и m. Заполните массив размером n×m в шахматном порядке: клетки одного цвета заполнены нулями, а другого цвета - заполнены числами натурального ряда сверху вниз, слева направо. В левом верхнем углу записано число 1.
Выведите полученный массив на экран, отводя на вывод каждого элемента ровно 4 символа.
Ввод | Вывод |
---|---|
3 5 |
1 0 2 0 3 |
По данным числам n и m заполните двумерный массив размером n×m числами от 1 до n×m по спирали, выходящей из левого верхнего угла и закрученной по часовой стрелке, как показано в примере. Выведите полученный массив, отводя на вывод каждого элемента ровно 4 символа.
Тесты к этой задаче закрытые.
Ввод | Вывод |
---|---|
4 5 |
1 2 3 4 5 |
На поле для игры в сапер клеточки с минами обозначаются символом “*”, а в каждой пустой клеточке записано число от 0 до 8, равное количеству мин в 8 клетках, соседних с данной.
Дан список мин на поле. Постройте по данному списку изображение поля.
Программа получает на вход числа N и M - количество строк и столбцов на поле, а также количество мин на поле K. Далее идет K пар чисел - координат мин. Первое число - номер строки, второе число - номер столбца.
Выведите изображение поля на экран, клетки при выводе разделяйте одним пробелом.
Тесты к этой задаче закрытые.
Ввод | Вывод |
---|---|
3 2 2 1 1 2 2 |
* 2 2 * 1 1 |
2 2 0 |
0 0 |
Дано натуральное число \(k\). Сделайте \(k\)-мерный список размера 2 по каждому измерению, то есть общее число элементов в списке должно быть \(2^k\). Заполните список нулями.
Выведите результат при помощи функции print
без дополнительного форматирования.
Ввод | Вывод |
---|---|
1 |
[0, 0] |
2 |
[[0, 0], [0, 0]] |
3 |
[[[0, 0], [0, 0]], [[0, 0], [0, 0]]] |
Дано натуральное число \(k\). Сделайте \(k\)-мерный список размера 2 по каждому измерению, то есть общее число элементов в списке должно быть \(2^k\).
Список заполните строковыми значениями по формуле: \[ A[i_1][i_2]...[i_k] = \mbox{str}(i_1)+\mbox{str}(i_2)+...+\mbox{str}(i_k) \]
Например, если k == 4
, то A[0][0][1][0] == '0010'
.
Выведите результат при помощи функции print
без дополнительного форматирования.
Ввод | Вывод |
---|---|
1 |
['0', '1'] |
2 |
[['00', '01'], ['10', '11']] |
3 |
[[['000', '001'], ['010', '011']], [['100', '101'], ['110', '111']]] |