Как научиться решать задачи по программированию
Перейти к содержимому

Как научиться решать задачи по программированию

  • автор:

Как решить задачу, если непонятно, с чего начать: советы от Хекслета

Как решить задачу, если непонятно, с чего начать: советы от Хекслета главное изображение

Все сталкиваются с трудностями при изучении нового: особенно при решении задач, которые отличаются от всего, что мы знали до этого. Постепенно вы поймете, какие подходы нужны для решения различных задач, но пока этого не случилось, приходится просто двигаться на ощупь. В этой статье мы дадим несколько советов, которые могут помочь с прохождением сложных практических уроков на Хекслете.

С чего начать

Обычно самое сложное в решении задачи — сделать первый шаг. Особенно на старте обучения, когда опыта ещё нет, может показаться, что вы совершенно ничего не понимаете и не способны решить даже самое простое упражнение. Если вы читаете задание и у вас нет никаких идей, с чего же вообще начать, мы предлагаем начинать с самых маленьких шагов.

Задания связаны напрямую с теорией, в том числе с пройденной в более ранних курсах. Вы всегда можете вернуться к каким-то урокам, чтобы освежить нужную тему. И так в любых ситуациях — если вы понимаете, что не хватает каких-то знаний, просто вернитесь к предыдущим урокам. Очень сложно запомнить всю информацию, поэтому возврат к уже пройденному материалу — это нормально.

Главный принцип решения задач — дробить задачу на подзадачи. Не пытайтесь сразу решить большое и сложное упражнение с первого подхода, делайте это постепенно. Если в задании сказано написать и экспортировать функцию, напишите пустую функцию и экспортируйте её. Ваш код в большинстве случаев уже будет работать, хоть и не проходить наших тестов. Проверьте примеры вызова функции, которую вам надо написать, посмотрите, что в неё передаётся. И так шаг за шагом продвигайтесь к реализации полного и нужного вам решения.

Ищем ошибки в коде

Важная часть работы над задачей — это поиск ошибок, который начинается с логов. Это то, что выводит программа во время своего выполнения. Например, когда вы запускаете проверку вашего решения во вкладке OUTPUT отображается вывод работы тестов — это и есть логи. Вы можете добавлять к этому выводу любой собственный вывод, используя инструменты своего языка программирования (например в JS — console.log() ).

Залогируйте входящие данные — это поможет понять, с чем придётся работать внутри функции. Как это сделать, мы рассказываем в наших справочных материалах. Для удобства вывода логов вы можете добавлять свои метки, чтобы видеть, какая именно переменная выводится. Например, так может выглядеть логирование в JS:

export default (first, second) =>  console.log('--------------------- START ------------------'); console.log('параметры:'); console.log(first); console.log(second); . console.log('Результат'); console.log(result); >; 

Отметка «START» нужна, чтобы увидеть, в какой именно момент вызывается ваша функция. Например, в упражнениях на Хекслете часто идёт проверка через тесты, которые несколько раз запускают нашу функцию с разными данными. Таким образом, в выводе информации можно будет легче разобраться, что и к какому запуску вашей функции относится.

Иногда вместо логирования гораздо удобнее использовать дебаггер. Например, если вы делаете упражнение, в котором есть Web-доступ, можно открыть DevTools браузера и посмотреть в нём исполняемый код. Здесь вы можете поставить на паузу выполнение программы и посмотреть, чему равны все значения переменных или констант в текущий момент.

Изолируем код

При знакомстве с задачей старайтесь сразу определять сложные моменты и максимально их прорабатывать. Например, если в решении нужно использовать цикл, а вы ещё плохо знакомы с ними, можно отдельно от решения попрактиковаться в их использовании. Старайтесь больше экспериментировать и подводить пример максимально близко к тому, что происходит в задаче.

Выделение изолированных участков кода — еще один важнейший механизм в решении задач. Попробуйте выделить в вашем алгоритме промежуточные результаты — так вы сможете написать отдельные модули, каждый из которых будет вычислять нужный результат. При этом логика таких модулей будет максимально простой и понятной. Тут мы подходим пожалуй к самой сложной вещи: построение алгоритма.

Описываем алгоритм

Решение любой задачи начинается с алгоритма, после чего уже идет его реализация. С ней обычно всё понятно: мы либо знаем, как нужно делать, либо не знаем — и вот тогда нужно искать информацию, читать документацию и так далее. Отдельным пунктом в реализации идёт работа над ошибками — об этом мы расскажем чуть позже.

Начните продумывать алгоритм без контекста языка программирования. Есть такое понятие как псевдокод — это конструкции, очень похожие на язык программирования, но не привязанные к какому-то конкретному языку. Они помогают составить алгоритм решения задачи и перенести его в код.

Попытайтесь описать решение простыми словами другому человеку. Есть даже такой приём, он называется «метод утёнка» — это когда вы описываете, что делает каждая строчка вашего кода воображаемому собеседнику (игрушечной уточке). Этот приём работает не только когда код уже написан, но и ещё при поиске верного алгоритма. Когда вы описываете проблему другому человеку, вам невольно приходится систематизировать всю информацию, формализовать некоторые идеи и возможные пути решения, а это уже первый шаг к составлению работающего алгоритма.

И не стесняйтесь просить помощи. Не стоит расстраиваться, что у вас не получается решить с первого раза. А когда задаёте вопрос, задавайте его правильно. Когда у вас уже есть какое-то решение, но оно не работает, наступает следующий этап работы.

Читайте также: Как сохранять фокус на протяжении всего обучения: советы от Хекслета

Проверяем каждую идею

Даже опытные программисты далеко не всегда с первого подхода реализуют правильное решение. Обычно создаётся первый, черновой вариант решения, и уже дальше он дорабатывается. В ходе работы над ошибками очень важно проверять каждый участок кода.

Постарайтесь проверить каждый промежуточный результат, залогируйте изменения данных, разберите на мелкие детали работу вашего кода. Одна из самых распространенных ошибок в программировании это построение дальнейшего решения на неверных выводах. Например, вы написали какой-то код и считаете, что он работает верно. Далее вы добавляете код, но что-то уже не работает как надо. Можно сделать вывод, что проблема в новом коде, однако вполне возможно, что просто изначальный код был не верен. Такая ситуация опасна тем, что вы можете потратить очень много времени впустую — потому что просто будете искать проблему не в том месте.

Чтобы избежать таких ситуаций, во-первых нужно перепроверять код, особенно когда вы еще только начинаете учиться. Старайтесь избегать утвердительных формулировок по типу «я сделал правильно» или «этот код делает то-то», если вы это точно не проверили. Во-вторых, вы можете показать своё решение другому человеку или с помощью метода утенка описать своими словами, что делает тот или иной участок кода. Есть большая вероятность, что вы сразу обнаружите слабые места в вашем решении, либо собеседник укажет на них.

Делаем шаг назад

Если долго не получается решить задачу, попробуйте отвлечься. Вы всегда можете вернуться к ней позже. Многим студентам часто приходили решения по утрам, а иногда — даже во сне. Также полезно возвращаться к старым задачам, особенно если вы уже подзабыли решения, либо если какая-то из тем кажется не до конца понятной. Помните, что какие бы ни были сложные задачи, все решения строятся на базовых простых вещах, как здание строится из маленьких кирпичиков.

Пройденный материал ещё полезно перепроходить и потому, что это хорошая подпитка вашей мотивации: вы будете быстрее решать уже пройденные задачи. Таким образом вы на себе почувствуете прогресс, это даст уверенности, что вы движетесь в правильном направлении.

Никогда не останавливайтесь: В программировании говорят, что нужно постоянно учиться даже для того, чтобы просто находиться на месте. Развивайтесь с нами — на Хекслете есть сотни курсов по разработке на разных языках и технологиях

10 шагов по решению задач в программировании

Это сборник советов для разработчиков-новичков, которые смотрят на пустой экран и не знают, с чего начать. Нередко можно услышать от молодых разработчиков, работающих над решением каких-то задач в программировании, что они не уверены, за что нужно хвататься. Ты понимаешь саму задачу, логику, основы синтаксиса и так далее. Если ты видишь чей-то код, или тебе кто-то помогает, то можно всё сделать самому. Но бывает, что ты не уверен в своих силах, или поначалу тебе трудно реализовать свои мысли в коде, несмотря на то, что ты знаешь синтаксис и логику. Под катом — несколько советов по решению этой проблемы, которые помогут вам в повседневной работе.

1. Прочитайте условия задачи как минимум трижды (или хотя бы столько раз, сколько вам будет удобно)

Вы не сможете решить задачу, если не поймёте её. Есть разница между задачей и задачей, которую, как вам кажется, вы решаете. Можно прочитать первые несколько строк, а насчёт остального выстроить предположения, поскольку всё выглядит похожим на то, с чем вы сталкивались раньше. Даже если вы делаете популярную игру наподобие Виселицы, удостоверьтесь, что прочитали все её правила, пусть даже вы играли в неё раньше.

Иногда можно попробовать объяснить задачу другу и посмотреть, поймёт ли он ваше объяснение. Вы же не хотите пройти половину пути и обнаружить, что неправильно поняли требования. Так что лучше потратить в начале больше времени, чтобы всё прояснить. Чем лучше поймёте задачу, тем легче будет её решить.

Допустим, мы создаём простую функцию selectEvenNumbers , которая берёт массив чисел и возвращает массив evenNumbers с одними лишь чётными числами. Если чётных чисел в исходном массиве нет, то массив evenNumbers возвращается пустым.

function selectEvenNumbers() < // здесь ваш код >

Какие вопросы можно себе задать:

  • Как компьютер может сказать, что число является чётным? Разделить на 2 и проверить, чтобы результат получился целым.
  • Что я передаю этой функции? Массив.
  • Что содержит этот массив? Одно или несколько чисел.
  • Какие типы данных у элементов массива? Числа.
  • Какова цель этой функции? Что я возвращаю в конце её выполнения? Цель — получить все чётные числа и вернуть их в массиве. Если нет чётных чисел, то массив возвращается пустым.

2. Пройдите по задаче вручную как минимум с тремя наборами данных

Возьмите лист бумаги и пройдите по задаче вручную. Выберите не менее трёх наборов данных для проверки. Выберите предельно допустимые и крайние случаи.

Предельно допустимые случаи: проблема или ситуация, возникающая за пределами нормальных параметров функционирования. Например, когда одновременно несколько переменных или состояний среды имеют экстремальные значения, даже если каждый из параметров находится в своём специфическом диапазоне.

Крайние случаи: проблемы или ситуации, возникающие только при экстремальных (минимальных или максимальных) значениях параметров функционирования.

Вот, к примеру, несколько наборов данных для использования:

[1]
[1, 2]
[1, 2, 3, 4, 5, 6]
[-200.25]
[-800.1, 2000, 3.1, -1000.25, 42, 600]

Когда только начинаешь, то зачастую пренебрегаешь какими-то шагами. Поскольку наш мозг уже знаком с чётными числами, то можно просто посмотреть на набор чисел и сразу передать в массив 2, 4, 6 и так далее, не думая о том, как наш мозг выбирает конкретные числа. Если вы замечаете это за собой, то лучше взять большой набор данных, чтобы помешать мозгу решать задачу, просто глядя на числа. Это поможет придерживаться настоящего алгоритма.

Давайте пройдём по массиву [1]

  1. Смотрим на единственный элемент массива [1] .
  2. Определяем, является ли он чётным. Не является.
  3. Замечаем, что других элементов в массиве нет.
  4. Определяем, что здесь нет чётных чисел.
  5. Возвращаем пустой массив.
  1. Смотрим на первый элемент массива [1, 2]
  2. Это 1 .
  3. Определяем, является ли он чётным. Не является.
  4. Смотрим на следующий элемент.
  5. Это 2 .
  6. Определяем, является ли он чётным. Является.
  7. Создаём массив evenNumbers и добавляем в него 2 .
  8. Замечаем, что других элементов в массиве нет.
  9. Возвращаем массив evenNumbers — [2] .

3. Упрощайте и оптимизируйте свой алгоритм

Поищите подходящие паттерны, может быть, что-то удастся обобщить. Подумайте, можно ли уменьшить количество шагов.

  1. Создадим функцию selectEvenNumbers .
  2. Создадим новый пустой массив evenNumbers для хранения чётных чисел.
  3. Проходим по каждому элементу массива [1, 2] .
  4. Находим первый элемент.
  5. Делим его на 2 и определяем, чётный ли он. Если да, то прибавляем к evenNumbers .
  6. Находим следующий элемент.
  7. Повторяем шаг №4.
  8. Повторяем шаги №5 и №4, пока не кончатся элементы в массиве.
  9. Возвращаем массив evenNumbers вне зависимости от того, есть ли в нём что-то.

  1. Доказываем истинность для n = 1 , n = 2 , .
  2. Предполагаем, что будет истинно для n = k .
  3. Доказываем истинность для n = k + 1 .

4. Пишите псевдокод

После проработки основных шагов напишите псевдокод, который можно перевести в настоящий код. Это поможет определить структуру кода, да и вообще облегчит его написание. Пишите псевдокод построчно. Это можно делать на бумаге или в виде комментариев в редакторе. Если вы только начинаете и считаете, что пустой экран выглядит жутковато или отвлекает, то лучше писать на бумаге.

В целом не существует правил для написания псевдокода, но можно включать синтаксис из вашего языка, если так будет удобнее. Но сосредотачивайтесь не на синтаксисе, а на логике и этапах алгоритма.

Применительно к нашему случаю есть много разных вариантов. Например, можно использовать filter , но ради простоты примера воспользуемся простым циклом for (однако при последующем рефакторинге мы ещё столкнёмся с filter ).

Вот пример псевдокода, в основном состоящего из слов:

function selectEvenNumbers создаём массив evenNumbers и делаем его эквивалентным пустому массиву для каждого элемента в этом массиве смотрим, является ли элемент чётным если чётный (при делении на 2 результат получается нецелым) добавляем его к массиву evenNumbers return evenNumbers

А вот псевдокод, в котором слов гораздо меньше:

function selectEvenNumbers evenNumbers = [] for i = 0 to i = length of evenNumbers if (element % 2 === 0) добавляем его к массиву evenNumbers return evenNumbers

Главное, писать код построчно и понимать логику каждой строки.

Вернитесь к задаче, чтобы удостовериться, что вы на правильном пути.

5. Преобразуйте псевдокод в нормальный код и отладьте его

Когда ваш псевдокод будет готов, преобразуйте каждую строку в реальный код на вашем языке. Здесь мы воспользуемся JavaScript.

Если вы писали на бумаге, то перенесите всё в редактор в виде комментариев, а затем замените каждую строку.

Теперь вызовите функцию и дайте ей некоторые из ранее использованных наборов данных. Так можно проверить, возвращает ли код нужный результат. Также можете написать тесты для проверки соответствия выходных данных ожидаемому результату.

selectEvenNumbers([1]) selectEvenNumbers([1, 2]) selectEvenNumbers([1, 2, 3, 4, 5, 6]) selectEvenNumbers([-200.25]) selectEvenNumbers([-800.1, 2000, 3.1, -1000.25, 42, 600])

После каждой переменной или строки можно использовать console.log() . Это поможет проверить, ведут ли себя значения и код так, как ожидается, прежде чем двигаться дальше. Таким образом вы выловите любые проблемы, не зайдя слишком далеко. Вот пример того, какие значения можно проверить при начале работы.

function selectEvenNumbers(arrayofNumbers) < let evenNumbers = [] console.log(evenNumbers) // Удаляем после проверки выходных данных console.log(arrayofNumbers) // Удаляем после проверки выходных данных >

Ниже приведён код, полученный после обработки каждой строки псевдокода. Символы // обозначают строки из псевдокода. Жирным выделен реальный код на JavaScript.

// function selectEvenNumbers function selectEvenNumbers(arrayofNumbers) // evenNumbers = [] let evenNumbers = [] // for i = 0 to i = length of evenNumbers for (var i = 0; i < arrayofNumbers.length; i++) // if (element % 2 === 0) if (arrayofNumbers[i] % 2 === 0) // добавляем его к массиву evenNumbers evenNumbers.push(arrayofNumbers[i]) > > // return evenNumbers return evenNumbers >

Уберём псевдокод, чтобы не путаться.

function selectEvenNumbers(arrayofNumbers) < let evenNumbers = [] for (var i = 0; i < arrayofNumbers.length; i++) < if (arrayofNumbers[i] % 2 === 0) < evenNumbers.push(arrayofNumbers[i]) >> return evenNumbers >

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

6. Упрощайте и оптимизируйте код

Возможно, вы заметили, что упрощение и оптимизация — это повторяющиеся темы.

«Простота — предпосылка надёжности».

Эдсгер Дейкстра, нидерландский учёный и один из первопроходцев в ряде областей информатики

В нашем примере одним из путей оптимизации будет фильтрация элементов в массиве посредством возвращения нового массива с помощью filter . В этом случае нам не нужно определять переменную evenNumbers , потому что filter вернёт новый массив с копиями элементов, которые соответствуют фильтру. При этом исходный массив не изменится. Также нам не нужно использовать цикл for . filter пройдёт по каждому элементу, и если вернёт true, то элемент попадёт в массив, а если false , то будет пропущен.

function selectEvenNumbers(arrayofNumbers) < let evenNumbers = arrayofNumbers.filter(n =>n % 2 === 0) return evenNumbers >

Может потребоваться несколько итераций упрощения и оптимизации кода, по мере того как вы будете находить новые способы.

Задавайте себе такие вопросы:

  • Каковы цели упрощения и оптимизации? Цели зависят от принятого в вашей команде стиля или ваших личных предпочтений. Вы пытаетесь максимально уплотнить код? Или вы хотите сделать его более читабельным? В таком случае вы можете добавить отдельные строки с определением переменной или вычислением чего-либо, а не пытаться всё сделать в одной строке.
  • Как ещё можно сделать код более читабельным?
  • Можно ли ещё уменьшить количество шагов?
  • Есть ли переменные или функции, которые не нужны или не используются?
  • Какие-то шаги повторяются? Посмотрите, можно ли определить в другой функции.
  • Существуют ли более эффективные способы обработки крайних случаев?

«Программы должны быть написаны так, чтобы люди их читали, и лишь во вторую очередь — чтобы машины их исполняли».

Джеральд Сассман и Гарольд Абельсон, авторы “Structure and Interpretation of Computer Programs”

7. Отлаживайте

Этот шаг необходимо выполнять в ходе всего процесса. Сквозная отладка поможет раньше выловить любые ошибки синтаксиса или недостатки логики. Воспользуйтесь преимуществами своего IDE (Integrated Development Environment) и отладчика. При обнаружении бага рекомендуется просматривать код построчно, стараясь найти неожиданные вещи. Несколько советов:

  • Читайте, что пишется в сообщения об ошибках в консоли. Иногда в них указываются номера строк для проверки. Это даст вам исходную точку для поисков, хотя иногда проблемы могут скрываться в других строках.
  • Комментируйте блоки кода или строки, а также выходные данные, чтобы быстро подмечать поведение кода. При необходимости код можно всегда раскомментировать.
  • Используйте другие образцы данных, если возникают непредусмотренные сценарии.
  • Сохраняйте разные версии файла, если применяете другие подходы. Не стоит терять наработанное, если захочется откатиться к прежнему решению!

«Самый эффективный инструмент отладки — тщательное продумывание в сочетании с разумно размещёнными командами вывода на экран».

Брайан Керниган, профессор информатики в Принстонском университете

8. Пишите полезные комментарии

Через месяц вы можете и не вспомнить, что означает каждая строка кода. А тот, кто будет работать с вашим кодом, вообще этого не знает. Поэтому важно писать полезные комментарии, чтобы избежать проблем и сэкономить впоследствии время, когда придётся снова вернуться к этому коду.

Избегайте таких комментариев:

// Это массив. Итерируем его.
// Это переменная.

Старайтесь писать короткие, высокоуровневые комментарии, которые помогут понять, что тут происходит, если это не очевидно. Это пригодится при решении сложных задач, вы сможете быстро понять, что делает конкретная функция, и почему. Благодаря использованию понятных комментариев и имён переменных и функций вы (и другие люди) сможете понять:

  • Для чего этот код?
  • Что он делает?

9. Получайте отзывы посредством ревизии кода

Получайте отзывы от коллег, руководителей и других разработчиков. Читайте Stack Overflow. Смотрите, как другие решали аналогичные задачи и учитесь у них. Нередко бывает несколько способов решения задачи. Узнайте, что они собой представляют, и вам будет быстрее и проще приходить к ним самостоятельно.

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

Дядя Боб Мартин, программный инженер и соавтор манифеста Agile

10. Практикуйтесь, практикуйтесь, практикуйтесь

Даже опытные разработчики постоянно практикуются и учатся. Если вы получили полезный отклик, внедрите его. Снова решите задачу, или аналогичные задачи. Заставляйте себя. С каждой решённой задачей вы становитесь лучше как разработчик. Радуйтесь каждому успеху и не забывайте, как много вы уже прошли. Помните, что программирование, как и любая деятельность, со временем будет даваться всё проще и легче.

«Гордитесь тем, сколько вы прошли. Верьте в то, что пройдёте ещё больше. Но не забывайте наслаждаться путешествием».

Майкл Джозефсон, основатель Института этики Джозефа и Эдны Джозефсон

Как Решать Задачи По Программированию

Наверное, у многих новичков бывало такое, когда ты смотришь решение какой-то задачи в Интернете или на уроке, читаешь чужой код и кажется что всё максимально просто и понятно. Но вот приступаю к решению такой же задачи самостоятельно, впадаешь в ступор. Что делать, с чего начать и т. д. Хотя казалась бы было всё было понятно. Знакомое чувство? С ним сталкивается каждый, кто только начинает изучать программирование. Поэтому сегодня я расскажу как решать зачади по программированию на языке Python, да и любом другом языке. Меня зовут Макс. Я один из авторов YouTube-канала PyLounge. Поехали!

Во-первых, ты должен чётко понимать, что от тебя требуется.

Как нельзя лучше сделать это тебе поможет декомпозиция. Декомпозиция — это когда ты разбиваешь одну большую сложную задачу на несколько мелких простых задача. При этом в момент дробления задачи не пытайся думать о программной реализации и программировании вообще. Старайся думать как ТЫ бы решал эту задачу, ты сам, будучи человеком. Опиши свои человеческие действия на каждом этапе. Перед этим вдумчиво прочитай текст задачи. Можно даже читать вслух. Часто проговаривание вслух помогает восприятию. И начинай декомпозировать с человеческой точки зрения.

Допустим перед нами стоит задача:

Написать функцию, которая получает из текстового файла словарь с настройками графики для игры.

Файл имеет следующий вид:

Начинаем смотреть на задачу глазами обычного человека. Вот у меня на Рабочем столе лежит текстовый файл. Чтобы мне прочитать содержимое файла его надо открыть. Соответственно это и есть первый пункт наше алгоритма — Открыть файл.

Далее я глазами вижу первую строчку файла. Здесь через пробел записаны два слова. Так как в файле записаны настройки графики то, очевидно, в каждой строчке хранится пара «название опции — её значение». Например, Разрешение 1920×1080. Соответственно я, будучи человеком, мысленно читаю первую строчку. Дальше мне нужно отделить «ключ настройки» от её значения. Как я будучи человеком понимаю, что в этой строчке два разных слова? Как я понимаю, что здесь не одно слово? Слова разделены между собой пробелами. Значит слово до пробела ключ, после значение. Это и есть следующий этап нашего алгоритма — читаем строку и делим её, за разделитель принимаем символ пробела. Затем первую половину строки заносим в ключ, вторую в значение.

Далее я будучи человеком, опускаю взгляд на следующую строку и повторяю описанное выше действие. Потом следующую и следующую. До тех пор, пока в файле не закончатся строки. Это и есть следующий шаг — по очереди обрабатывать каждую строчку из файла.

Теперь у меня в голове (или в переменной типа dict (словарь)) имеется вся нужная информация. По аналогии с функцией мы возвращаем словарь с данными. Потом я закрываю файл. Вот у нас и есть по сути готовый алгоритм:

1. Открыть файл.
2. Читаем строку из файла.
3. Делим её на две части через символ пробела.
4. Записываем первую часть строки в «ключ», а второю в «значение ключа» (например, ключ vsync — значение ключа off).
5. Аналогичным образом по очереди обрабатываем каждую следующую строку. Пока строчки в файл не кончатся.
6. Закрываем файл.
7. Сообщаем результат.

Можно для себя набросать псевдокод. То есть описание каждого шага алгоритма не на конкретно языке программирования, а абстрактно, на русском. Также неплохим вариантом может являться нарисовать блок-схему.

Псевдокод — это изложенные простым языком шаги алгоритма. Иными словами, это пошаговый план решения задачи. Если вы и так чётко понимаете процесс или задача относительно простая, то псевдокод и схему можно пропустить.

Теперь когда у нас имеется алгоритм, надо задать себе два вопроса:

1. Что мы имеем на вход (входящие данные).
2. Что мы имеем на выходе.

Снова смотри с позиции обычного человека. Чтобы я, будучи человеком, смог открыть какой-то файл и прочитать его, я должен знать где он лежит. Значит на вход мы и наша функция получает путь до файла.

Также в условии уже сказано, что мы должны сформировать словарь настроек. Значит словарь с ключами и значениями (куда сохраняются данные из файла) мы и должны вернуть из функции (вывести результат).

Теперь пытаемся переложить это на программный код. Также построчно всё проговаривая:

import os def read_settings_file(file_name): settings = dict() file = open(file_name, 'r') for row in file.readlines(): key, value = row.split(' ') settings[key] = value file.close() return settings print(read_settings_file('D://game_settings.txt')

Очень важно давать осмысленные и понятные названия переменным и функция. Это помогает делать код более читаемым и ты сам не запутаешься, если откроешь его спустя неделю. Рекомендую посмотреть наше видео «4 Совета Которые Помогут Сделать Твой Код Лучше».

Также стоит подумать, какие ошибки у нас могут возникнуть. Опять таки, задаём себе вопросы, например:

1. Что делать если файл не будет существовать?

Надо сделать проверку, добавить обработку такой ситуации.

2. Что случится если структура файла будет другой?
3. Кодировка файла будет нестандартной?
Нужно придумать как можно больше таких вопросов. И ответить на каждый из них, реализовав программное решение с помощью исключений, сообщений об ошибках и т.д.

Теперь когда у нас есть рабочее решение на руках, надо подумать, как его можно улучшить. То есть надо провести рефакторинг кода и сделать решение более эффективным.

Рефакторинг — это процесс улучшения кода, когда мы переписываем какие-то участки кода, которые можно сделать лучше.

При рефакторинге можно задавать себе следующие вопросы:
1. Можно ли получить этот результат как-то иначе? Какие еще подходы есть?
2. Понятно ли это решение с первого взгляда?
3. Можно ли использовать результат или метод для какой-то другой задачи?
4. Можно ли улучшить производительность решения?
5. Как эту задачу решают другие люди?

Никогда не пренебрегай внутренним диалогом с собой. Составляй план, блок-схему и т. д. Многие люди не делают этого, им кажется, что это бесполезная трата времени. Но на самом деле именно в этом и кроется ключевой момент в решении любой задачи.

В нашем случае мы могли бы работать с файлом через менеджер контекста, чтобы явно не вызывать функцию close () и метод readlines (). И применить к значением настроек функцию strip (), что бы не оставлять в строке символы переноса, табуляции и т. д. В случае с Python можно ещё и аннотации типов добавить:

from typing import Optional, Dict import os def read_settings_file(file_name:str) -> Optional[str]: if not os.path.exists(file_name): return None settings:Dict[str, str] = dict() with open(file_name, 'r') as file: for row in file: key, value = row.split(' ') settings[key] = value.strip() return settings print(read_settings_file('D://game_settings.txt')

К слову, очень важно смотреть, как другие решали подобную задачу. Так читая чужой код вы набираетесь опыта и вырабатываете надсмотренность. В чужом коде можно подсмотреть интересные решения, которые затем взять себе на вооружение.

Я в своё время очень часто смотрел чужие решения, сравнивал их со своим и это сильно мне помогло. Главное не смотреть ответ сразу) А именно сравнивать своё решение с чужим, если сам ну никак не можешь сделать.

Я привел пример простой задачи. Но более сложная задача будет отличаться лишь количеством этапов и инструментами, которые будет необходимо применить.

Запомните, умение решать задачи — это навык. Чем больше практики, тем лучше вам это будет удаваться. Если вы хотите много раз подтягиваться, то надо подтягиваться. Если вы хотите научиться быстро бегать, то надо бегать. Если вы хотите научиться решать задачи по программированию, то надо решать задачи. Истина всегда на поверхности.

Также есть чуть более подробная видеоверсия этой статьи на YouTube:

Как решать задачи на программирование

Перевод статьи «How to Solve Coding Problems with a Simple Four Step Method».

Я потратила два месяца на подготовку к своему первому техническому собеседованию и думала, что уже готова. Но когда подошла к нему уже вплотную, внезапно меня озарило: я ж понятия не имею, как решать задачи на программирование.

Ни в одном туториале из тех, по которым я училась программированию, не рассказывалось о решении задач. А мне определенно нужно было овладеть этим искусством: от этого зависела вся моя будущая карьера разработчика. И я немедленно взялась за поиски.

То, что я нашла, было не просто подходом, а бесценной стратегией. Это был проверенный временем алгоритм действий в четыре шага, который по какой-то причине остался незамеченным в сфере разработки.

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

Решение задач — это не только часть процедуры собеседований. Это то, чем разработчики занимаются ежедневно. В конечном итоге, само написание кода — это и есть решение задач.

Универсальный подход к решению задач

Этот метод изложен в книге «Как решать задачу» Дьёрдя Пойа. Первое издание вышло еще в 1945 году, было продано больше миллиона экземпляров. (На русском языке книга публиковалась как пособие для учителей еще в 1959 году. — Прим. перев.).

Метод Пойа используют многие программисты, от профессоров информатики (см. курс «Intro to CS» на Udacity, который ведет профессор Дэвид Эванс) до преподавателей современной веб-разработки вроде Кольта Стила.

Давайте пройдемся по решению простой задачи на программирование с применением метода Пойа. Это позволит увидеть работу метода на практике и в результате лучше разобраться в нем. Для примера будем использовать язык JavaScript.

Создайте функцию, которая будет складывать два числа и возвращать их сумму.

Вот четыре шага по решению любой задачи:

  1. Понять задачу.
  2. Разработать план.
  3. Осуществить план.
  4. Оглянуться назад.

«Во-первых, мы должны понять задачу; мы должны ясно видеть, что в ней является искомым. Во-вторых, мы должны усмотреть, как связаны друг с другом различные элементы задачи, как неизвестное связано с данными. Это необходимо, чтобы получить представление о решении, чтобы составить план. В-третьих, мы осуществляем наш план. В-четвертых, оглядываясь назад на полученное решение, мы вновь изучаем и анализируем его», — «Как решать задачу», 1959 г.

Давайте сделаем первый шаг.

Шаг 1: понять задачу

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

Тем не менее, постарайтесь удержаться. Прежде чем приступать к решению задачи, убедитесь, что вы хорошо поняли, что от вас требуется.

Прочтите текст задачи. Можно даже читать вслух, если это поможет вам притормозить.

Прочитав текст задачи, выясните все моменты, которые вам не понятны. Если дело происходит на собеседовании, можно задать уточняющие вопросы интервьюеру. Если вы решаете задачу в гордом одиночестве, обдумайте непонятные части или даже поищите в Google ответы на возникшие вопросы.

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

Чтобы помочь себе разобраться, спросите себя:

Каковы здесь входящие данные?

Какого рода input-ы следует ожидать? В нашем примере это аргументы, принимаемые функцией.

Читая текст задачи, мы понимаем, что входящими данными будут числа. Если подходить к делу более скрупулезно, мы можем спросить:

  • всегда ли будет только два числа?
  • что будет, если функция получит в качестве входящих данных три числа?

Эти вопросы мы можем задать интервьюеру или поискать ответ в описании задачи. (К задаче может прилагаться примечание типа «Исходите из того, что в функцию всегда будут передаваться только два числа». Конечно, это сразу все прояснит).

Можно задаться и другими вопросами. Всегда ли входящими данными будут числа? Что должна делать функция, если получит в качестве аргументов «a» и «b»? Уточните, всегда ли input будет числовым.

В качестве варианта — можно записать вероятные входящие данные в комментарии к коду, чтобы иметь представление о том, как они должны выглядеть.

// inputs: 2, 4

Далее следует спросить себя:

Каковы должны быть результаты?

Что функция будет возвращать? В нашем случае это должно быть оно число — сумма двух чисел, переданных в качестве аргументов. Убедитесь, что вы хорошо понимаете, каким должен быть output.

Придумайте простые примеры

Разобравшись в сути задачи и зная вероятные input-ы и output-ы, можно начать работать над конкретными примерами.

Примеры также могут использоваться для тестирования вашего решения. На техническом собеседовании или при подготовке к нему на сайтах вроде Codewars или HackerRank используются специальные редакторы. Большинство из них содержат уже готовые примеры или test cases. Несмотря на это, написание собственных примеров может помочь вам упрочить понимание задачи.

Начните с написания одного-двух простых примеров.

Давайте вернемся к нашей складывающей функции. Назовем ее «add».

Каким может быть input? Ну, допустим, таким:

// add(2, 3)

Каким будет результат при таких входящих данных? Записать это можно так:

// add(2, 3) ---> 5

Это показывает, что наша функция принимает в качестве input 2 и 3, а как output возвращает 5.

Придумайте сложные примеры

Продумывая более сложные примеры, вы можете уделить время поиску крайних случаев, которые стоит учесть.

Например, что будет, если наши входящие данные будут не числами, а строками? Что, если мы получим в качестве аргументов две строки, например, add(‘a’, ‘b’)?

Ваш интервьюер может сказать вам вернуть сообщение об ошибке, если входящих данных не будет или если они будут не того типа. В таком случае вы можете добавить соответствующий комментарий — в качестве напоминания себе.

// вернуть error, если input-ы - не числа.

Как вариант, интервьюер может сказать, что входящие данные всегда будут числами. В таком случае вам не понадобится писать никакой дополнительный код для обработки этого крайнего случая.

Если вы не на собеседовании, а просто решаете задачу, в ней может быть обозначено, что должно происходить при вводе невалидных данных.

Например, в задаче может говориться «При отсутствии input-а верните undefined». В таком случае можно написать комментарий:

// Проверить, если ли входящие данные. // Если входящих данных нет, вернуть undefined.

В нашем случае мы будем исходить из того, что input всегда будет числовым. Но в общем всегда лучше подумать о крайних случаях.

Профессор информатики Эванс советует писать т. н. безопасный код. Всегда думайте о том, что может пойти не по плану и как защитить свой код от возможных ошибок.

Прежде чем перейти ко второму шагу, давайте кратко повторим, что нужно сделать на первом шаге:

  • прочитать задачу
  • выяснить, какими будут входящие данные
  • выяснить, каким должен быть результат
  • создать простые примеры, затем — более сложные.

Шаг 2: разработать план решения задачи

Далее нужно составить план того, как вы, собственно, собираетесь решать задачу. Придумав план, запишите его в виде псевдокода.

Псевдокод — это изложенные простым языком шаги алгоритма. Иными словами, это пошаговый план решения задачи.

Опишите каждый этап решения. Если задача сложная, этапов может быть много. Если говорить о нашей задаче, мы можем написать:

// Создать переменную sum. // Сложить первый input со вторым, используя оператор сложения. // Сохранить значение суммы input-ов в переменной sum. // Вернуть переменную sum в качестве output.

Теперь у вас есть четырехэтапный план решения задачи.

Для более сложных задач профессор Эванс советует: «Полагайтесь на то, как задачи решаются людьми». То есть, забудьте на мгновение о том, как задачу может решить код, и подумайте о том, как ее решали бы вы — человек. Это может помочь вам более четко увидеть нужные шаги.

3. Шаг 3: осуществить план (решить задачу!)

Следующий шаг — собственно решение задачи. Руководствуясь псевдокодом, напишите настоящий код.

Профессор Эванс рекомендует сфокусироваться на простом, механическом решении. Чем проще и легче ваше решение, тем вероятнее, что вы напишете код правильно.

Если взять наш псевдокод, мы можем написать следующее:

function add(a, b)

Помните, что не следует преждевременно оптимизировать код. Написав решение, вы можете подумать, что ваш код неэффективный, и захотеть его улучшить. Но для начала создайте простое, механическое решение.

Что, если вы не можете решить задачу полностью? Например, если вы так и не нашли решения для какой-то ее части? Кольт Стил советует в таких ситуациях игнорировать эту сложную часть. Сконцентрируйтесь на всем остальном — том, что вы уже можете написать. Когда напишете, возвращайтесь к части, которая вызвала у вас затруднения.

Шаг 4: оглянуться назад

Когда у вас на руках будет готовое рабочее решение, подумайте, как его можно улучшить. На этом этапе можно провести рефакторинг и преобразовать свое решение в более эффективное.

Просматривая свою работу, вы можете задать себе несколько вопросов:

  • Можно ли получить этот результат как-то иначе? Какие еще подходы есть?
  • Понятно ли это решение с первого взгляда?
  • Можно ли использовать результат или метод для какой-то другой задачи?
  • Можно ли улучшить производительность решения?
  • Не приходят ли вам на ум какие-то способы рефакторинга для этого решения?
  • Как эту задачу решают другие люди?

Возвращаясь к нашему коду, мы можем сделать его более лаконичным, если удалим нашу переменную и используем имплицитный return:

function add(a, b)

Дойдя до четвертого шага, вы понимаете, что можете никогда не довести свое решение до совершенства. Даже великие разработчики пишут код, который впоследствии хотят изменить. Так что вопросы из приведенного списка — лишь направляющие, которые могут вам помочь.

Если вы решаете задачу на собеседовании, то для четвертого шага у вас может просто не остаться времени. Впрочем, если время есть, попробуйте улучшить свое решение. Ну а если вы просто решаете какую-нибудь задачу, обязательно проходите все описанные шаги.

Когда я практиковалась в решении задач, я практически всегда смотрела и чужие решения, которые часто были элегантнее и эффективнее моих.

Итоги

В этой статье мы рассмотрели четырехэтапную стратегию решения задач на программирование. Давайте повторим:

  • Шаг 1: понять задачу
  • Шаг2: создать пошаговый план решения
  • Шаг 3: реализовать план и написать код решения
  • Шаг 4: оглянуться назад и по возможности улучшить решение.

Применение этого подхода очень помогло мне при прохождении технических собеседований, да и вообще в моей работе.

Если вы не чувствуете себя уверенно, решая задачи, помните, что умение решать задачи — это навык. Чем больше практики, тем лучше вам это будет удаваться.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *