[Exam] PHP Basics - 12 Януари 2015 - решения, впечатления, резултати
Здравейте,
веднъж и аз да стартирам такава тема :) Моето лично мнение е, че на поправителни / повишителни изпити, особено като са струпани в 4 дни един след друг е хубаво, ако не с една идея по - лесни то в никакъв случай по - трудни задачи от тези на редовната сесия. Мнението ми може да се потвърди и от 50% нулеви резултати на днешния изпит а бих казал, че имаше подобно леко "изхъвляне" в една от задачките на JS също. Идеята ми е че с подобен тип задачи хората който са на кантар да се откажат .. биват отказвани, а това е лоши и за тах и за Софтуни.
Ето мойте решения GitHub
Ще се радвам да прочета мненията ви за днешния изпит.
PP: Ако някой може сам да измисли алгоритъм за пълнене на спираловидна матрица в рамките на час и нещо, без да е решавал нещо подобно до момента лично ще му стисна ръката и ще го черпя бира. Ма наистина сам да я измисли, не да "преведе" алгоритъма от джава или C#
значи аз имах голям късмет с датата че открих решение на твоето затруднение почти моментално. Ако ползваш ООП синтаксиса когато не успее да генерира дата дава грешка трика тук е че ако ползваш процедурния синтаксис date_create то той ако не успее да направи дата връща false което решава задачата доста лесно. (справка виж моето решение). А иначе явно някъде съм пропуснал тая задача с спираловидната матрица в c# щото после забелязах че маса народ са я ярешили със 100 точки а са се затруднили на предните задачки. Та както казах не е лесно да измислиш алгоритъм за пълнене на спираловидна матрица под напрежение за час и нещо. Аз лично намеих код в интернет и го преведох на php това ми отне 2 часа (не намирах работещ код) останалото решение с палиндроми ( или както им е там името ) ми отне 15 мин. Аз лично бях потресен от скоростта на filkolev тои имасше 387 точки в 11 и нещо :) Явно възраста ми си казва думата и затъпявам :)
За задачи с дати се бях подготвил още от редовния изпит, където разучих подробно DateTime, пак за 1-ва задача. Спирална матрица решавах за последния курс по C#, една за подготовка и една, която дадохме на изпит. 4-та беше много стандартна и като цяло по-лесна от предишни такива, давани на PHP. На това отдавам краткото време, за което ги направих тези трите.
Иначе статистиката: в 11:44 - 350 т., в 12:30 - 387 т., 13:36 - 400 т. Да кажем от 3:30 мин общо, 2 часа ми заминаха да мъча 2-ра, от тях 1 час борба конкретно с тест 8.
Виждам, че са качили материалите от изпита, интересно ми е да го видя въпросния тест и защо ми беше толкова трудно да го хвана.
mar0der, прав си за date_create. Промених си малко решението на първа задача в github. Доста кратка и лесна логически стана. И на мен ще ми е интересно защо на втора толкова време се мъчих с последния тест. Хубавото в случая беше, че като пуснах един submit само с принтиране на No matches видях, че на два теста вземам точки и единия беше именно 8-ми. Това доста помогна.
За regex-a на втора не е нужно да се използва lookahead, а вместо това може да се сложи само \d. Моят regex така съм го направил, че ако махна това \d вземам само 50 точки.
Filkolev при мен разликата между тоя тест последния да не работи и да работи е само лукахеда
nikola.m.nikolov прав си май кат се замисля и /d ще свърши работа.
"P.S. ако някой има желание мога да му обясня логиката на пълнене на спиралната матрица."
Аз имам желание :)
Така и не ги реших тия задачи, още от C# Basics
Velio, ами използвам 6 променливи специално за пълнене на матрицата.
$direction = 1;
$x = 0;
$y = $length - 1;
$xCount = $rows - 1;
$yCount = $length - 1;
$char = 0;
$x и $y ги използвам за определяне на индекса на двумерната матрица и съответстват на редове и колони.
$xCount ми служи да определя колко цикъла по x трябва да направя (за да пълня на даден ред), преди да сменя посоката и да пълня по колони. $yCount е аналогично, като с него пълно по колони.
$char е лесно - това е индекса на стринга, от който взимам символите и пълня с тези символи спиралата
$direction служи да определя посоката на пълнене на спиралата - ако е 1 тогава пълня първо надолу по редовете, след което започвам да пълня наляво по колоните. Ако е -1 започвам да пълня нагоре по редовете, след което започвам да пълня надясно по колоните.
В конкретната задача от ред 13 до ред 16 създавам масив от еднакви по дължина стрингове, съставени само от *. Това се явява първоначално празната спирала.
Съществената част за пълнене на спиралата е от ред 18 до 40.
Създавам for цикъл, който върти от първия до последния ред на спиралата. В него имам веднага вложен цикъл, който върти по колони. Ако сме на нулевия ред то го пълня с първите символи от стринга. Ако спиралата има 7 колони то взимам първите 7 символа от стринга. Ако е с 4 колони, то взимам първите 4 символа от стринга със символите. При всяко завъртане на цикъла увеличавам char++.
Ако обърнеш внимание при инициализирането $x съм го задал да е 0, защото започваме от нулевия ред да пълним спиралата. $y нарочно не съм го инициализирал с 0, а директно с $lenght - 1. Все пак е ясно, че като запълни първия ред $y винаги ще стигне до $lenght - 1. $lenght e броя колони. Можеше и да инициализирам $y = 0 и при пълненето на първия ред на спиралата да увеличавам $y++ на всеки цикъл.
След като напълня първия ред идва момента с $direction. Както казах за $direction - при 1 пълня надолу и след това наляво, а при -1 пълня нагоре и след това надясно. Тези две пълнения ги правя с последните 2 цикъла. С първия пълня по редове, затова променям само стойността на $x. За да определя дали $x да намалява или да се увеличава използва $direction. Ако $direction = 1, следователно трябва да пълня надолу по редовете, т.е. $x трябва да се увеличава. Така се получава следната формула $x = $x + 1 * $direction. Ако $direction = 1 имаме $x = $x + 1 * 1, т.е. $x ще се увеличи. Ако $direction = -1 следователно $x = $x + 1 * -1 т.е. ще се намали. Като свършат двата цикъла за пълнене по $x и $y обръщам $direction с $direction *= -1.
$xCount и $yCount ги използвам за да определя колко пъти да въртя най-вътрешните 2 цикъла, с които пълня спиралата. Ако имаме матрица с 5 реда и 5 колони я пълня по следния начин - първо запълвам целия първи ред и стигам до края. След това пълня 4 реда надолу и 4 реда наляво и намалявам с 1. После пълня 3 реда нагоре и 3 реда надясно и пак намалявам с 1. Така пълно докато $xCount и $yCount не станат 0-ли. Когато матрицата е квадратна то може да се ползва само 1 променлива. Когато обаче е правоъгълна се налага да се използват $xCount и $yCount.
Благодаря за подробното обяснение :)
Схванах каква е логиката, утре ще ти дебъгна и решението да разгледам как работи.
Не съм вече в състояние в такъв час да обмислям обяснението на Никола, но ще го прочета на свежа глава утре.
Да споделя все пак и аз логиката на пълнене с while цикли.
В случая използвам факта, че трябва да напълним точно N*N елемента. Инициализирам матрицата, като задавам на всяка клетка стойност false, това показва, че дадената клетка все още не е била запълнена. В типизираните езици може да се подходи по друг начин, примерно да се сложи стойност, която да я ясно, че няма да бъде добавена впоследствие в матрицата, или пък да се направи отделна матрица с булеви стойности, която единствено да следи кои клетки от основната матрица са вече запълнени.
Имам променлива, която изпълнява две функции едновременно - 1) следи кой индекс от стринга трябва да хвана, за да добавя символа в дадената клетка; 2) брои попълнените вече клетки. Главният цикъл приключва, когато са запълнени N*N клекти.
В главния цикъл има 4 вложени while цикъла, като всеки от тях пълни матрицата в определена посока, в случая първият пълни по колони надясно, вторият надолу по редове и т.н. Т.е. започвайки от кой да е ъгъл на матрицата аз мога доста лесно да променя начина на пълнене като разменя поредността на циклите.
Имам две променливи, които следят текущия ред и текущата колона. На всяко завъртане на вътрешен цикъл увеличавам съответната променлива, т.е. цикълът, който върви надясно, увеличава колоните, цикълът, който върви в посока нагоре, намалява редовете и т.н.
Всеки от тези 4 цикъла се върти докато: 1) не стигне границите на матрицата или 2) не стигне до стойност, която вече е била запълнена. При което този цикъл приключва и започва следващият, който сменя посоката.
След всеки един цикъл трябва да се обновят стойностите на реда и колоната, така че новата позиция да е клетката, която трябва да бъде напълнена първа от следващия цикъл. С чисто визуален пример много лесно се вижда кое как да се коригира; например, след приключване на цикъла, който върви надясно, трябва на увеличим реда, за да слезем на следващия (следващата посока е надолу) и да намалим колоната, понеже сме излезли от рамките на матрицата или сме отишли в ред, който е вече запълнен.
Както споделих малко по-горе, доста ми е интуитивна тази логика и много лесно се намират грешки ако има такива. Аз допуснах 1-2 на изпита, трябваха ми не повече от 5 минути да ги оправя, защото всяка една стъпка ми е пределно ясна и разбираема.