На этом этапе вы почти закончили решение. Осталась только одна последняя функция, sudoku_solve():
# sudokusolve.py def sudoku_solve(input_string): grid = line_to_grid(input_string) answer = solve(grid, 0, 0) if answer: return grid_to_line(answer) else: return "Unsolvable"
Эта функция делает три вещи:
Вот и все! Вы прошли через решение проблемы решателя судоку.
Интервью для обсуждения
Решение Sudoku solver, через которое вы только что прошли, — это хороший код для ситуации интервью. Частью процесса собеседования, скорее всего, будет обсуждение некоторых кодов и, что более важно, некоторых компромиссов в дизайне, которые вы сделали. Давайте рассмотрим некоторые из этих компромиссов.
Самое большое дизайнерское решение вращается вокруг использования рекурсии. Можно написать нерекурсивное решение для любой задачи, которая имеет рекурсивное решение. Почему рекурсия предпочтительнее другого варианта?
Это обсуждение, которое зависит не только от проблемы, но и от разработчиков, участвующих в написании и поддержании решения. Некоторые проблемы поддаются довольно чистым рекурсивным решениям, а некоторые-нет.
Как правило, рекурсивные решения требуют больше времени для запуска и использования большего объема памяти, чем нерекурсивные решения. Но это не всегда так, и, что более важно, это не всегда так важный.
Точно так же некоторые команды разработчиков чувствуют себя комфортно с рекурсивными решениями, в то время как другие находят их экзотическими или излишне сложными. Ремонтопригодность также должна сыграть свою роль в ваших проектных решениях.
Одна хорошая дискуссия, о решении, вокруг производительности. Как быстро должно выполняться это решение? Будет ли он использоваться для решения миллиардов головоломок или только нескольких? Будет ли она работать на маленькой встроенной системе с ограничениями памяти или на большом сервере?
Эти внешние факторы могут помочь вам решить, какое дизайнерское решение лучше. Это отличный темы для обсуждения в интервью, когда вы работаете над проблемой или обсуждаете код. У одного продукта могут быть места, где производительность критична (например, трассировка лучей на графическом алгоритме), и места, где это вообще не имеет значения (например, разбор номера версии во время установки).
Обсуждение подобных тем во время интервью показывает, что вы не только думаете о решении абстрактной проблемы, но и готовы и способны поднять ее на новый уровень и решить конкретную проблему, стоящую перед командой.
Иногда стоит выбрать решение, которое медленнее, чтобы сделать решение, с которым легче работать, отлаживать и расширять. Решение в задаче Sudoku solver преобразовать структуру данных в сетку является одним из таких решений.
Это проектное решение, вероятно, замедляет программу, но если вы не измерили, вы не знаете. Даже если это так, приведение структуры данных в форму, естественную для данной проблемы, может облегчить понимание кода.
Вполне возможно написать решатель, который работает с линейными строками, которые вы получаете в качестве входных данных. Это, вероятно, быстрее и, вероятно, занимает меньше памяти, но small_square() помимо всего прочего, в этой версии будет намного сложнее писать, читать и поддерживать.
Еще одна вещь, которую нужно обсудить с интервьюером, будь то живое кодирование или обсуждение кода, написанного в автономном режиме, — это ошибки и ложные повороты, которые вы сделали на этом пути.
Это немного менее очевидно и может быть немного вредно, но особенно если вы живете кодированием, делая шаг к рефакторингу кода, который не является правильным или может быть лучше, вы можете показать, как вы работаете. Мало кто из разработчиков может написать идеальный код с первого раза. Черт возьми, мало кто из разработчиков умеет писать хорошо код в первый раз.
Хорошие разработчики пишут код, а затем возвращаются, рефакторируют его и исправляют. Например, наша первая реализация detect_possible() выглядит так:
# sudokusolve.py def first_detect_possible(x, y, grid): print(f"position [{x}][{y}] = {grid[x][y]}") possible = set(range(1, 10)) # Тест горизонтальный for index, value in enumerate(grid[x]): if index != y: if grid[x][index] != 0: possible.remove(grid[x][index]) # Тест вертикальный for index, row in enumerate(grid): if index != x: if grid[index][y] != 0: possible.remove(grid[index][y]) print(possible)
Игнорируя то, что он не учитывает small_square(), этот код может быть улучшен. Если вы сравните это с окончательной версией detect_possible() выше вы увидите, что окончательная версия использует один цикл для тестирования обоих горизонтальных и вертикальное измерение.
Это конец вашего приключения с практическими проблемами Python!
Поздравляем с проработкой этого набора практических задач Python! Вы получили некоторую практику применения своих навыков Python, а также потратили некоторое время на размышления о том, как вы можете реагировать в различных ситуациях собеседования.
В этой статье вы узнали, как:
Удачи с интервью!
Начало: