24 май 2016 г.

Как да подобрим алгоритмичното си мислене (в 3 стъпки)

Е, признавам си, не съм особено добър в решаването на сложни задачи по програмиране. Започнах преди едва 2 години и истината е, че все още изпитвам затруднения и се чувствам сякаш едва прохождам.

Имайки това предвид - нещата, които ще напиша тук се базират само и единствено на личния ми опит. Не съм master математик с хиляди медали от състезания и има изключително много материал, който тепърва започвам да схващам.

Но въпреки това имам прогрес. Тази година за пръв път се пуснах на олимпиада по програмиране и (по чудо!) дори се класирах за национален кръг (с отбора ми).

Искам да ви споделя как точно стана това.



Credits: http://class-central.com/



В първия семестър на първата година в университета (реално когато започнах да програмирам) се чувствах все едно съм попаднал в джунглата. Не мислех, че ще очакват от нас да "знаем" какво правим, но се оказа противоположното. Напълно липсваше този период, в който те "държат за ръката" и те потупват по рамото ако успееш да изведеш на конзолата "Hello World".

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

На края на семестъра имахме контролно за освобождаване от изпит по програмиране. Явих се на това контролно и изживяването се оказа като шамар в лицето, защото не можах да реша нито една от задачите. Тогава осъзнах, че ако го карам по този начин, няма да стигна до никъде. Затова седнах и си казах, че активно ще решавам задачи и ще чета теория, свързана с програмирането, само и само да подобря уменията си малко или много (а и да взема успешно изпита си, разбира се), всеки ден.

Имах късмет, че поне от университета ни бяха предоставили изключително много задачи. Проблемът беше, че не знаех какво правя, нямаше кой да ми каже как и защо нещата работят по определен начин. Дори имах трудност да формулирам въпрос, който да напиша в Google (ако някой преподавател чете това - това е причината студентите никога да нямат въпроси). Самите задачи нямаха решения и като цяло ми липсваше насока...

Започнах с елементарни задачи, изискващи използването на условни конструкции, цикли, въвеждане/извеждане на информация на конзолата, масиви. Дори и това ми се стори трудно в началото, но успях да си изградя една скромна основа, с която да продължа напред. Процесът беше доста предсказуем - започвам да решавам задачата, стигам до някъде, опитвам се да намеря решението за известен период от време и търся обяснения в интернет, успешно решавам задачата или просто продължавам със следващата.

Проблемът беше, че често просто не ми идваха никакви идеи за решение на задачите. Макар да мисля, че практиката (т.е. писането на програми) е хиляди пъти по-важно от теорията, няма как да направиш асоциация от рода на "аха, тук трябва да използвам масив!" ако никога не си чувал за подобно нещо. Така че, малко или много - теорията е необходима. Но за жалост не винаги теорията ми беше поднесена в линеен, последователен вид, а често ми се налагаше да я намирам частица по частица и по този начин да оформям решението на пъзела в главата си.

Как реших този проблем? Google, форуми, разпитване, решаване, зацикляне, решаване, зацикляне. В един момент просто информацията се подреди в главата ми и по-лесно започнаха да ми идват идеи за решения. Но в никакъв случай това не се случи бързо.

И така... първото и най-основно нещо, е, разбира се...


1. Решавайте задачи (дори трудните)!


Сигурно до болка сте чували вече, че за да станеш добър в каквото и да било, се изисква много практика. Програмирането, от това, което съм видял, не е никакво изключение. 

Колкото повече задачи решавате, толкова по-добри ще станете в решаването им по-нататък. Няма кратък път, който да поемете и който ще ви направи елитни програмисти за една седмица.

Важно е да започнете с елементарните задачи. Причината е, че това просто повдига самочувствието и дава увереността, която е нужна, за да се опитаме да решим по-сложна задача. Лично при мен - ако започна със сложна задача и забележа, че не мога да я реша - това ме отказва и от лесните задачи. Моят съвет е - почнете с лесните задачи.

Другото ключово нещо е, че НЕ Е важно дали ще успеете да решите конкретната задача. Знанията ви се развиват дори и без да стигнете до крайния отговор. 

Не ползвайте това като оправдание да се откажете бързо, но просто знайте, че дори и да не стигнете до решение на задачата, сте станали по-добри, просто защото сте вложили някаква мисъл, проучили сте потенциални решения в интернет и ако не друго, поне сте развили малко "психическата издръжливост", която се изисква при решаването на сложни задачи (затова мисля, че олимпиадите по програмиране са страхотна идея). Печелите и в двата случая.

Решаването на задачи е страхотно, защото едва когато имаме задача пред себе си, мозъкът ни автоматично започва селективно да се фокусира върху нея и да търси решения. Започват да ви идват въпроси, които пък ви водят до решения. Е, ако не сте решавали много задачи, както казах, няма да ви идват много качествени въпроси или решения, но всичко това се гради с времето.

Един страхотен сайт, който в момента ползвам, за да развия собствените си умения, е HackerRank.


2. Погледнете решенията на другите!


Не е достатъчно само да пишем код, трябва и да свикнем да четем този на другите. Това е нещо, от което аз все още не съм се възползвал достатъчно, но е много добър инструмент. 

Особено за по-сложни задачи, да видиш решението на друг е много полезно, защото ти позволява да проследиш логиката ред по ред и това, от своя страна, води до тези "аха" моменти, в които просто започваме да разбираме дадена идея и можем да я приложим в собствените си програми.

Понякога имам лошия рефлекс да видя някое по-сложно решение, което не разбирам, и да търся по-просто, защото първото е някак си "плашещо". Но това, според мен, е грешен подход. 

Когато видим сложно решение, по-добрият вариант е да го третираме както бихме третирали непозната дума в текст на чужд език. Виждаме непознатото нещо и започваме да го проучваме - това за какво е, как работи и така нататък. 

Отново искам да напомня, че не е важно да разберем всичко и да го разберем на сто процента - достатъчно е да влезем малко по-дълбоко от това, с което сме свикнали и пак ще развием знанията си.


3. По-малко четене на теория (но все пак я четете)!


От моя опит, алгоритмите (и измислянето на алгоритми) не се научават с четене на теория. Разбира се, както казах, трябва да имаме някаква предварителна основа и да имаме понятие за какво става въпрос, но обикновено ни трябва много по-малко информация, отколкото си мислим.

Изключително грешно е мисленето от рода на "ако само прочета достатъчно теория ще съм перфектно подготвен и ще мога да реша всяка задача". Е, не става така, пробвах! Обикновено вместо това прочитате теорията и се заблуждавате, че разбирате материала, но когато седнете да решавате конкретна задача осъзнавате, че едва ли не сте си загубили времето във всичкото това четене, когато сте можели просто да решавате...

Истината е, че не сте загубили времето си когато сте чели теорията. Теорията е полезна. Просто без да сте решавали задачи, мозъкът ни не може да направи връзката с прочетеното. Чак когато се помъчите малко ще започнете да си спомняте прочетеното и да ви идват по-качествени идеи и решения.

Също така, не се опитвайте да научавате алгоритми наизуст. Излишно е. Ако сте имплементирали например алгоритъм за сортиране десетки пъти, няма да ви е нужно да го знаете стъпка по стъпка, защото разбирате принципа му на работа и лесно ще се сетите как да го използвате в конкретен случай.

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

---

Това са най-важните неща, които научих досега за развиването на алгоритмичното мислене! Както казах, и аз тепърва навлизам в дълбоките води... и на мен ми е трудно. Но смятам, че няма никаква магия в това да подобрим алгоритмичното си мислене, което е ключово за всеки програмист. Никой не се е родил научен и само с практика можем да станем по-добри.

Peace out!