top of page
Post: Blog2_Post

Uzun müddət üzərində düşündüyüm MIT məsələsinin cavabı

Uzun müddətdir, Molla Nəsrəddindən danışmırıq. Ona görə qərara gəldim, söhbətimizə kiçik bir lətifə ilə başlayım: deməli, bir gün Molla Nəsrəddindən soruşurlar ki, göydə neçə ulduz var? Molla da cavab verir:

- Mənim eşşəyimin tükü qədər. Əgər inanmırsınızsa, ikisini də sayıb baxa bilərsiniz.


Göydəki ulduzları, Mollanın eşşəyinin tüklərinin sayını tapa bilmərik, amma mətndəki hərfləri saya bilərik. Elə keçən dəfə elan etdiyimiz məsələdəki kimi.

Ötən həftə sizə ünvanladığımız sualın cavabını hazırladıq. Əgər kodları daha rahat icra edərək öyrənmək istəyirisinizsə, bu bloqu "Kaggle" platforması üzərindən də oxuya bilərsiniz.


Gəlin ilk öncə, nə istədiyimizi dəqiqləşdirək: bizə verilən mətndə ən uzun alfabetik ardıcıllıq lazımdır. Deməli, biz iki iş görürük:



Məsələn, mətn eyni zamanda "abc" "jklmn" birləşmələri varsa, onda funksiyamızın nəticəsi yalnızca "jklmn" olmalıdır.


İlk işdən başlayaq.


Əlifba sırası ilə yazılan hərflərin müəyyən edilməsi


Dəyişənlərin müəyyən edilməsi

Bu tapşırığın həll olunması üçün "loop"-lardan (yəni dövrlərdən) istifadə edəcəyik. Lakin ilk öncə bəzi dəyişənləri müəyyən etməliyik:

maxlen = 0
collect = '-'
letters = 'sssssabcdebobobegghiaklmno'
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

"letters" dəyişəni üzərində əməliyyat aparacağımız mətndir. Digər dəyişənləri isə növbəti mərhələlərdə izah edəcəyik.


Hərflərin sırası

Python-da ədədlərin ASCII koda əsasən sırasını müəyyən edən ord() funksiyası var. Əgər funksiyaya "a" veriləni daxil etsəniz, 97 cavabı çıxaracaq. chr() funksiyası isə verilən sıra nömrəsində yerləşən hərfi tapır.

In [5]: ord('a')
Out[5]:

In [5]: chr(98)
Out[5]: 'b'
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Bu funksiya bizə ardıcıl hərfləri tapmaqda kömək edəcək.


chr(ord(x) + 1) yazdığımız zaman x dəyişəninə mənimsədilmiş hərfdən sonra gələn hərfi tapa bilərik. Yəni x = "b" olduqda, chr(ord(x) + 1) ifadəsinin cavabı "c" olacaq. Bu ifadənin sayəsində bizə verilən mətndəki istənilən hərfdən sonra gələn hərfi tapa bilərik.


1)

if letters[i+1] == chr(ord(letters[i])+1):

Yuxarıdakı şərti ifadə "letters" dəyişənində (i+1)-ci sırada duran elementin i-ci sırada duran elementin əlifba sırasındakı qonşusuna bərabər olmasını yoxlayır. Yəni i-ci element "a"-dırsa, (i+1)-ci element "b" olmalıdır.



Mətn dəyişəninə yeni hərf əlavə etmək

Xatırlayırsınızsa, yuxarıda "collect" dəyişənimiz var idi. "letters" mətnində ard-arda gələn əlifba qonşularını bu dəyişənə əlavə edirik. Yəni bizə lazım olan ardıcıl hərfləri bu dəyişənin içində toplayırıq.


2)

collect = collect + letters[i:i+2]

letters[ i : i + 2 ] bizə i-ci elementdən etibarən yanaşı gələn iki elementi, yəni i və (i+1)-ci elementləri verir. (i+2)-ci element isə aralığa daxil edilmir.


Sonlu dövrlər ("for" loops)

Qeyd etdiyimiz şərti ifadəni "for loop" (for = üçün) vasitəsilə "letters" mətnində sonuncu hərf xaricində bütün elementlər üçün tətbiq edirik. Sonuncu elementdən sonra heç birelement gəlmədiyi üçün ardıcıllığı yoxlamağa ehtiyac yoxdur. Ona görə "loop"-u aşağıdakı kimi tərtib edirik:


3)

for i in range(len(letters)-1):

Yuxarıdakı 3 mərhələni birləşdirdiyimiz zaman ortaya bu nəticə çıxır:


for i in range(len(letters)-1):
    if chr(ord(letters[i])+1) == letters[i+1]:               
                   collect = collect + letters[i:i+2]
                   print(collect)
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Tərarlanan hərflərin qarşısının alınması

Yuxarıdakı ifadənin nəticəsinə fikir versək görərik ki, "collect" dəyişənində eyni hərflər təkrarlanır. Yəni biz "abcde" görmək istəyirdiksə, funksiya bizə "abbccdde" nəticəsi verir. Bunun qarşısını almaq üçün şərti ifadəmizə bir budaq da artırırıq:


- Əgər "collect" dəyişəninin son elementi "letters"-in i-ci (yəni bizim yoxladığımız) elementinə bərabərdirsə, onda mətnə sadəcə (i+1)-ci elelement birləşdirilsin.


Bu kodun işləmə prinsipi belədir: Deyək ki, i = 5. Biz 5-ci element üçün kodu icra edəndə, 5-ci (i) 6-cı (i+1) elementlərin müvafiq olaraq "a""b" olduğunu gördük və onu "collect" dəyişəninə birləşdirdik. Nəticədə collect = "-ab" oldu. Biz "for loop" işlətdiyimiz üçün eyni şey yenidən 6-cı element üçün təkrarlanacaq (növbəti iterasiyada i = 6 olacaq). Bu dəfə 6-cı (i) elementin "b" olduğunu bilirik və görürük ki, 7-ci (i + 1) element "c"-dir. Biz "bc" mətnini yuxarıdakı kodla birbaşa "collect"-ə əlavə etsəydik, nəticə "-abbc" olardı. Lakin, aşağıda "if" şərti bağlaması vasitisilə "collect"-in son elementinin i-ci elementə bərabər olduğunu müəyyən edirik:

 if collect[-1] == letters[i]:

collect[-1] == "c" letters[i] == "c" doğru olduğuna görə, şərti ifadə doğrudur və təkrarçılıqdan (duplicate) qaçmaq üçün i deyil, (i+1) elementi "collect"-ə əlavə olunur.

for i in range(len(letters)-1):
    if chr(ord(letters[i])+1) == letters[i+1]:
                if collect[-1] == letters[i]:
                   collect = collect + letters[i+1]
                else:
                   collect = collect + letters[i:i+2]
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Qeyd: Dəyişənə "-" işarəsinə mənimsətməyimizin səbəbi "slicing" prosesi zamanı xəta verməməsidir. Əgər mətn dəyişənin "" (yəni boşluq) kimi saxlasaq, o zaman collect[-1] indeksi, və ya collect[ len(collect) - 1 ] (yəni sonuncu elementi) seçmək istədikdə, xəta ilə qarşılaşacağıq.

In [1]: a = ""
     a[-1]

IndexError: string index out of range
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Artıq kodumuz verilən mətndə əlifba qonşularını tapdıqda nə etməli olduğunu bilir:


---- > mətndəki elementi və onun qonşusunu yoxlayır;

---- > elementlər əlifba sırası ilə ardıcıl gəlirsə, təkrarçılığın qarşısını almaq üçün hər dəfə "collect"-in son elementini yoxlayır;

---- > onları "collect"-ə əlavə edir;

---- > mətndəki axırıncı element istisna olmaqla, bütün elementlər üçün prosesi təkrarlayır.


Şərt doğru olmadıqda...

Əgər if chr(ord(s[i])+1) == s[i+1]: şərti səhvdirsə, kod heç bir şey etmir və növbəti iterasiyaya keçir. Sonda belə bir şey alınır:

-abcdeabcdghiklmno

Burada bir neçə ayrı alfabetik ardıcıllıq bir-birinə bitişik yazılıb. Biz isə onları ayırmalı və hansının daha uzun olduğunu müqayisə edə bilməliyik. Yəni ehtiyacımız olan format aşağıdakı kimidir:

-abcde-abcd-ghi-klmno

Buna görə ayırıcı işarəyə ehtiyacımız var. Yəni növbəti iterasiyada hərf əlifba sırasını pozursa, o zaman "collect" mətninə ayırıcı işarə əlavə olunsun. Bunu aşağıdakı kodla etmək mümkündür:

elif chr(ord(letters[i])+1) != letters[i+1]:
        collect = collect + '-'
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Təkralanan "-" işarəsi

Yazdığımız formulun mənfi cəhəti odur ki, ardıcıllığı pozan hər hərfin yerinə "-" işarəsi əlavə edəcək. Yəni belə bir nəticə alınacaq:

------abcde-----abcd----ghi--klmno

Biz isə belə bir nəticə istəyirik:

-abcde-abcd-ghi-klmno

Bunun üçün aşağıdakı şərti ifadəni yazırıq:

elif chr(ord(letters[i])+1) != letters[i+1]:
        if collect[-1] != '-':
                collect = collect + '-'
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Bu kodda əgər "collect" mətninin sonunda "-" işarəsi varsa, onun yanına ikinci bir "-" işarəsi əlavə olunmur.


Ən uzun ardıcıllığının tapılması


Ardıcıllıqların uzunluqlarının tapılması

Artıq collect == "-abcde-abcd-ghi-klmno" nəticəsini əldə etdik, və bununla ilk işimiz bitdi. Növbəti işimiz, burada ən uzun ardıcıllıqları tapmaqdır. Yuxarıda "maxlen" dəyişəni yaratmışdıq. Həmin dəyişən vasitəsilə ən uzun ardıcıllığın neçə elementdən ibarət olduğunu tapırıq və "maxlen" dəyişəninə mənimsədirik:

for a in collect.split('-'):
    if len(a) > maxlen:
        maxlen = len(a)
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Hər iterasiyda collect.split('-') "list"-nin içində olan hər "a" (yəni element) üçün uzunluğun maxlenin bir əvvəlki dəyərindən böyük olub-olmadığı yoxlanılır və sonda ən böyük dəyər saxlanılır. Burada collect.split('-') verilən mətni seçdiyimiz ayırıcıya əsasən (burada "-") hissələrə bölərək "list" halına gətirir ( collect.split('-') = ['', 'abcde', 'abcd', 'ghi', 'klmno'] )


Ən uzun ardıcıllığının çıxarılması

Daha sonra uzunluğu "maxlen"-ə bərabər olan (yəni ən uzun olan) ardıcıllığı tapırıq və ekrana çap (print) edirik:

for a in collect.split('-'):
    if len(a) == maxlen:
        print(a)
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Son nəticə

Ümumi olaraq kodun görüntüsü belədir. Ən sonda def vasitəsilə onu funksiyaya çevirə və istifadə edə bilərik:

def find_alphabet(letters):
    maxlen = 0
    collect = '-'
    for i in range(len(letters)-1):
        if chr(ord(letters[i])+1) == letters[i+1]:
                    #print(letters[i:i+2])
                    if collect[-1] == letters[i]:
                       collect = collect + letters[i+1]
                    else:
                       collect = collect + letters[i:i+2]
                    #print(collect)
        elif chr(ord(letters[i])+1) != letters[i+1]:
            if collect[-1] != '-':
                    collect = collect + '-'
                    #print(collect)
                    
    for a in collect.split('-'):
        if len(a) > maxlen:
            maxlen = len(a)
    for a in collect.split('-'):
        if len(a) == maxlen:
            return a
s = 'sssssabcdebobobegghiaklmno'
find_alphabet(s)
Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Digər məsələnin həlli də bunun kimidir, lakin orada, if chr(ord(letters[i])+1) == letters[i+1]: deyil, if letters[i] == letters[i+1]: şərti doğru olmalıdır.


Kodu "Kaggle"-da icra etmək üçün buraya klikləyin.

Ümid edirəm, paylaşım sizin üçün faydalı oldu. Daha çox belə skriptlər üçün "Kaggle" üzərindən bizi izləyə bilərsiniz:




146 views0 comments

Recent Posts

See All

Comments


Digər

bottom of page