Modele de algoritmi în #Excel – Binary search algorithm (14)

Continui seria de articole despre algoritmii clasici din programare cu o metodă de rezolvare a problemelor de căutare descrise în articolul de pe Codility: https://app.codility.com/programmers/lessons/14-binary_search_algorithm/

Ar trebui să specificăm de la începutul articolului că metodele de rezolvare propuse nu sunt poate cele mai optime din punct de vedere al vitezei de procesare, dar sunt un mod interesant de a demonstra că Excelul este mult mai mult decât A1+B2 și fiecare dintre utilizatorii de Excel pot găsi funcții și formule interesante pe care să le aplice în diverse domenii și operații pe care le efectuează în activitatea lor.

Dacă sunteți doar în căutarea unor funcții de căutare, vă reamintesc un articol mai vechi Funcția Filter() din #Excel 365 în care sunt descrise comparativ mai multe funcții de căutare din Excel.

În articolul curent forța Excelului este demonstrată prin funcțiile MAKEARRAY() și SCAN() într-o construcție specială. Veți vedea.

Nu avem numaidecât o parte de teorie în afara algoritmului descris la începutul articolului. Ambele probleme în schimb mi-au dat destul de multă bătaie de cap cu înțelegerea cerințelor. Cred că aici este de fapt dificultatea lor.

Problema MinMaxDivision

Această problemă este orientată pentru a determina care este minimul sumei unor numere din poziții consecutive dintr-un vector, dacă îl împarți în K părți de diferite dimensiuni. Un aspect ciudat al problemei este că vectorul poate fi împărțit în elemente vide. De exemplu dacă ai un vector de 7 elemente și un K de 3 poți împărți vectorul în 3 segmente de 7, 0, 0. Suma tuturor numerelor din vectorul de 7 este suma maximă care poate fi atinsă. Scopul este să îl împarți în segmente a căror sumă maximă să fie cea mai mică din toate formele de a împărți elementele.

În problemă este introdus și termenul M care reprezintă de fapt dimensiunea maximă a valorilor din vectorul A. Această valoare M trebuie să fie mai mică decât minimul de maximum combinații.

Propunerea de rezolvare

MinMaxDivision rezolvare pas cu pas.

În primă fază a rezolvării problemei nu am înțeles numaidecât că numărul K reprezintă numărul de segmente în care se poate împărți șirul și am ralizat un calcul de însumare a tuturor combinațiilor de numerele consecutive în E9.

Funcția din E9: =MAP(C9#;LAMBDA(v;SUM(INDEX(D9#;SEQUENCE(3;;v)))))

în care în MAP() refer secvența de numere generate pe dimensiunea vectorului -2. Valoarea de -2 este pentru a preveni erorile în funcție datorate indexării în afara vectorului. În acest fel ultima poziție de indexare v este dimensiunea vectorului -2 ceea ce înseamnă că valoarea 3 din Sequence() de final va face indexarea până la finalul vectorului D9#.

Pentru cei mai puțin familiarizați cu funcțiile dinamice un index() poate aduce mai multe elemente dintr-un vector dacă specificăm acest lucru prin SEQUENCE(3) sau ROW(1:3) de exemplu. Eu prefer SEQUENCE pentru că poți specifica valori dinamice, pe când ROW() nu funcționează cu variabile.

Pentru a înțelege toate combinațiile posibile am generat o matrice în I5 în care indexez lista de elemente consecutive în ordinea lui r: câte unul, câte două, câte 3… și așa mai departe. Formula din I5 este:

=MAKEARRAY(ROWS(A4#);ROWS(A4#);LAMBDA(r;c;IFERROR(TEXTJOIN(";";TRUE;INDEX(D9#;SEQUENCE(r;;c)));"")))

în care pentru a putea aduce și afișa valorile din vectorul D9# folosesc funcția TEXTJOIN(). Magic în această formulă este indexul de secvență de r valori începând de la coloana c.

A fost destul de dificil să ajung la această abstractizare. Ulterior în I14 am înlocuit TEXTJOIN() cu SUM() de indexare dinamică pentru a calcula valorile fiecărui segment.

În Q14 am utilizat funcția =MAX(I14:O14) pentru a determina maximul pe fiecare linie, după care în R14 am filtrat doar valorile mai mari decât M, obținând apoi prin MIN() valoarea 7.

Integrați toți acești pași dau următoarea formulă:

=LET(sir; --TEXTSPLIT(B1;;",");
     _k;E2; _m; F2; _rs; ROWS(sir);
     matrix; MAKEARRAY(_rs;_rs;LAMBDA(r;c;IFERROR(SUM(INDEX(sir;SEQUENCE(r;;c)));"")));
     _maxs; BYROW(matrix;MAX);
     return; MIN(FILTER(_maxs; _maxs>_m));
return)

Frumos în această formulă este variabila _maxs care aplică noua formă de utilizare a BYROW() în cadrul tabelelor fără a folosi separat o LAMBDA() care ar complica problema.

Exemplu practic: Alocarea unui buget de investiții

O companie are un buget total de investiții pe care trebuie să-l împartă între mai multe proiecte. Problema constă în împărțirea optimă a bugetului astfel încât suma maximă alocată unui singur proiect să fie cât mai mică posibil.

Datele problemei:
Ai N proiecte de investiții (echivalentul secțiunilor dintr-un șir de numere).
Fiecare proiect necesită o anumită sumă de bani (vectorul A din problemă).
Ai K departamente (echivalentul lui K din problemă), iar fiecare departament trebuie să gestioneze un set de proiecte.
Scopul este să împarți proiectele între cele K departamente astfel încât suma maximă alocată unui singur departament să fie minimizată.

Exemplu numeric:
Să presupunem că avem 5 proiecte care necesită următoarele sume de bani (în milioane):
A = [2, 1, 5, 1, 2, 2, 2]

Și trebuie să le alocăm la K = 3 departamente.

Obiectiv: Împărțirea optimă astfel încât suma maximă cheltuită de un singur departament să fie minimizată.

Posibile împărțiri
O posibilă împărțire ar fi:
[2, 1, 5] | [1, 2] | [2, 2]
Sumele alocate fiecărui departament: 8, 3, 4
Maximul este 8 (prima grupă).

O altă împărțire mai echilibrată:
[2, 1] | [5, 1] | [2, 2, 2]
Sumele alocate: 3, 6, 6
Maximul este 6 – mai echilibrat decât primul caz.

Problema NailingPlanks

În această problemă este vorba despre optimizarea numărului de cuie (C) care pot fi folosite pentru fixarea unui set de scânduri A-B.

Ca orice problemă de optimizare și aceasta este destul de dificilă de abordat pentru că avem foarte multe excepții. De exemplu cuiul din poziția 4 poate fișa și scândura 1 cât și scândura 2, ceea ce înseamnă că nu mai are sens să folosim cuiul din poziția 2 care poate fixa doar scândura 1. Cu ajutorul cuielor 6 și 7 putem fixa scândura 3, deci nu are sens să îl folosim pe al doilea.

NailingPlanks propunere de rezolvare in Excel

În rezolvarea problemei am căutat în G2 și H2 în ce interval de valori din A și B se află valoarea poziției cuiului. îmn XMATCH() am folosit parametrul -1 (egal sau mai mic decât valoarea căutată) pentru capătul de jos al scândurii (A) iar pentru capăt B am folosit parametrul 1 (egal sau mai mare decât valoarea căutată). Acesta este artificiul de căutare în intervale de numere prin XMATCH()

Ca să văd dacă un cui fixează mai multe scânduri în J2 am făcut o concatenare de numere unice. Rezultatul prelucrării anterioare fiind de tipul unui vector pe linie, ca să pot aplica funcția UNIQUE(), trebuie transpozate numerele rezultat, funcția de unicitate funcționează doar la nivel de vectori în coloană. Al doilea TRANSPOSE() nu este numaidecât obligatoriu atât timp cât folosesc TEXTJOIN() dar pentru a vedea rezultatele pe parcurs atunci l-am utilizat.

Partea cea mai dificilă dincolo de G2 și H2 a fost să determin care scândură a fost inserată cu un cui și să o elimin din rezultat. Pentru asta am abordat cu SCAN() în K2. Formula din K2 este:

=SCAN(0;J2:J6;LAMBDA(a;v; IF(a=0; v;
      LET(_a; TEXTSPLIT(a; ";");
          _v; TEXTSPLIT(v; ";");
          ver; IFNA(XMATCH(_v;_a;0);0);
          fil; TEXTJOIN(";";TRUE;FILTER(_v;ver=0;""));
          TEXTJOIN(";";TRUE;a;fil)))))

Ca să pot prelucra și compara numerele în variabila ver, a trebuit să descompun întâi valorile acumulatorului a și a valorii curente v. Dacă nici una din valorile curente nu se găsesc în ce a fost anterior, facem join între valoarea curentă și cea acumulată. Dacă valorile sunt deja în șir atunci aducem doar valoarea existentă.

Această formulă este foarte utilă pentru a putea compara șiruri de numere între ele și a acumula doar numărul care nu a mai fost. Exemplificare de extragere a tuturor valorilor unice dintr-un vector de valori

Functie de returnare a valorilor unice dintr-un vectori de valori multiple.

Funcția REDUCE() din D2 imi aduce doar rezultatul final al unui SCAN() fără a mai fi necesară trecerea prin fiecare etapă. Funcția din D2 este identică cu cea prezentată anterior doar că în loc de SCAN am folosit Reduce. Pentru a determina valorile în ordinea lor în D4 am introdus formula: =SORT(TEXTSPLIT(D2;;”;”))

Aceasta este cea mai de valoroasă funcție din acest articol, după opinia mea.

Revenind la problema inițială, în celula L2 am introdus o nouă funcție de scanare pentru a determina valorile unice din Scan 1 în poziția lor inițială. Apoi pentru a determina poziția cuielor am folosit Filtrarea în N2 apoi indexarea în O2 pentru a afla scândurile fixate de acele cuie.

Aparent complicat, dar soluționabil. Ar trebui testate pentru mai multe seturi de valori pentru îmbunătățirea soluției.

Pentru integrarea funcție trebuie avut în vedere că folosesc un Textjoin care nu funcționează într-un Byrow pentru construcția variabilei Dist, deci trebuie construită o funcție recursivă (fReqDist) anterioară. În final formula ar fi:

=LET(_a; B2:B5; _b; C2:C5; _c; E2:E6;
    CapatA; IFNA(XMATCH(_c;_a;-1);"");
    CapatB; IFNA(XMATCH(_c;_b;1);"");
    fReqDist; LAMBDA(v; TEXTJOIN(";";TRUE;(UNIQUE(TRANSPOSE(v)))));
    tabi; HSTACK(CapatA; CapatB);
    Dist; BYROW(tabi; LAMBDA(r; fReqDist(r)));
    Scan1; SCAN(0;Dist;LAMBDA(a;v; IF(a=0; v;
          LET(_a; TEXTSPLIT(a; ";");
          _v; TEXTSPLIT(v; ";");
          ver; IFNA(XMATCH(_v;_a;0);0);
          fil; TEXTJOIN(";";TRUE;FILTER(_v;ver=0;""));
          TEXTJOIN(";";TRUE;a;fil)))));
    Scan2; SCAN("";Scan1;LAMBDA(a;v; IF(a="";v;IF(v=a;"";v))));
    Cuie; FILTER(_c;--(Scan2="")=0);
    Scanduri; INDEX(Dist;XMATCH(Cuie;_c;0));
    Result; HSTACK(Cuie;Scanduri);
Result
)

Având în vedere complexitatea problemei sunt și cazuri pe care soluția oferită nu oferă răspunsul optim. Exemplificare:

Exemplu de problemă care nu are soluție optimă.

În această problemă optimul ar fi două cuie… poziția 5 și 7 sau 5 și 9, dar rezolvarea propusă anterior are o mică problemă cu scan-ul pentru prima valoare. Mi-ar plăcea să văd dacă un cititor poate să-mi trimită o soluție mai corectă pentru cazurile particulare.

Cam atât pentru astăzi.

Sper să fie util cuiva!

Modele de algoritmi în #Excel – Fibonacci numbers (13.2) – Ladder

Acest articol este o continuare a articolului despre numerele Fibonacci: Modele de algoritmi în #Excel – Fibonacci numbers (13) – Partea 1 – FibFrog și prezintă o metodă de rezolvare a problemei Ladder de pe site-ul Codility: https://app.codility.com/programmers/lessons/13-fibonacci_numbers/ladder/

Odată rezolvată problema șirurilor Fibonacci explicată în articolul anterior, această problemă nu are nimic special, atât timp cât autorii problemei explică în detaliu modul de rezolvare.

Pe scurt, problema presupune calcularea numărului de combinații prin care se poate urca o scară de dimensiune N pâșind una sau două trepte.

Datele de intrare ale problemei sunt doi vectori A și B în care:

Vectorul A: Numărul de trepte pentru fiecare scară
Fiecare element A[i] din vectorul A reprezintă numărul de trepte pentru o anumită scară.
De exemplu, dacă A = [4, 3, 5], atunci avem trei scări:
Prima scară are 4 trepte
A doua scară are 3 trepte
A treia scară are 5 trepte
Practic, fiecare element al lui A definește dimensiunea unei scări pentru care trebuie să calculăm numărul de moduri în care putem ajunge în vârf.

Vectorul B: Modulo pentru fiecare scară
Fiecare element B[i] din vectorul B reprezintă valoarea modulo 2^B[i] care trebuie aplicată rezultatului.
Deoarece valorile Fibonacci cresc foarte rapid, trebuie să calculăm rezultatul modulo 2^B[i] pentru a evita depășirea limitelor numerice.
De exemplu, dacă B = [3, 2, 4], atunci:
Pentru prima scară, rezultatul trebuie modulo 2^3=8
Pentru a doua scară, rezultatul trebuie modulo 2^2=4

Rolul lui B este să controleze dimensiunea rezultatului final pentru fiecare scară, evitând numere prea mari.

Rezolvare problema în Excel

Problema Ladder, rezolvare Excel.

În care:

D2 – Care este maximul sir Fibonnaci +1
În problema Ladder, folosim Fibonacci(N+1) pentru că trebuie să numărăm modurile distincte de a urca scara.
Fibonacci(N+1) se bazează pe faptul că pentru a ajunge la treapta 𝑁 putem veni fie de la 𝑁 − 1 (1 pas), fie de la 𝑁 − 2 (2 pași).

E2 – Puterile lui 2 la valoarea lui B

F2 – Se calculeaza restul impartirii numarului Fibonaci rezultat la puterile lui B

Funcția _fFibonacciSir() a fost introdusă și explicată în articolul anterior.

Rezolvarea integrată a problemei printr-o singură formulă cu funcții recursive nesalvate anterior ar fi:

=LET(_a; A2:A6; _b; B2:B6;
     fReqFibSir; LAMBDA(n; (((1+SQRT(5))/2)^SEQUENCE(n)-((1-SQRT(5))/2)^SEQUENCE(n))/SQRT(5));
      fibocat; MAP(_a; LAMBDA(v; MAX(fReqFibSir(v+1))));
      PuteriB; MAP(_b; LAMBDA(v; 2^v));
      return; MOD(fibocat;PuteriB);
return)

în care locul funcției presalvate _fFibonacciSir() este luat de funcția recursivă: fReqFibSir.

De remarcat în această formulă faptul să în partea de return am aplicat MOD() pentru cei 2 vectori cu număr de elemente egale, fără a întâmpina nici un fel de eroare.

Cam atât pentru acest articol!

Sper să fie util cuiva!

Modele de algoritmi în #Excel – Fibonacci numbers (13) – Partea 1 – FibFrog

De data aceasta mi-a dat greu! :) De aceea am decis să împart articolul despre numerele Fibonacci în două părți: una pentru problema FibFrog și a doua pentru Ladder. Pentru cititorii care au reușit să urmărească aceste serii complicate de programare funcțională în Excel, poate au observat că în articole sunt vehiculate permanent aceleași funcții, doar cu construcții și cazuri de utilizare diferite.

Pentru acest articol vă propun o metodă de rezolvare a problemei FibFrog de pe site-ul Codility: https://app.codility.com/programmers/lessons/13-fibonacci_numbers/. Trebuie știut că la data publicării acestui articol, nici un instrument de AI nu poate rezolva problema corect în Excel.

Să începem ca de obicei cu …

Un pic de teorie

Sunt foarte multe materiale de studiu pentru numerele Fibonacci pe Internet, ele stârnind interesul multor autori datorită aplicabilității pe scară largă a acestei secvențe.

Secvența Fibonacci este o succesiune recursivă definită de relația de recurență:

F(n)=F(n−1)+F(n−2)

unde F(0)=0 și F(1)=1. Aceasta are multiple aplicații în informatică, inclusiv în algoritmi de optimizare, structuri de date (heap Fibonacci), analiza complexității algoritmilor (divide et impera) și generarea de chei criptografice. Secvența este, de asemenea, utilizată în probleme de programare dinamică și este strâns legată de numărul de aur, având proprietăți logaritmice utile în analiza complexității algoritmilor.

Una din cele mai interesante metode de a calcula șirurile de numere este dată de formula:

Formula de calcul a numerelor Fibonacci. Sursa: https://codility.com/media/train/11-Fibonacci.pdf

Pentru a implementa această formulă în Excel utilizăm cu precădere funcția SQRT() pentru calculul radical și SEQUENCE() pentru valoarea lui n.

Rezolvare numere Fibonacci în Excel.

Având în vedere că în rezolvarea problemei am nevoie permanentă de această construcție introduc în acest articol funcția _fFibonacciSir() cu parametrul N pe care o voi reutiliza ulterior.

=LAMBDA(n; DROP((((1 + SQRT(5)) / 2) ^ SEQUENCE(n) - ((1 - SQRT(5)) / 2) ^ SEQUENCE(n)) / SQRT(5); 1))

Funcția DROP o utilizez pentru a elimina prima linie din șir, în așa fel încât să rămân cu o singură valoare 1 în rezultat.

În același timp o variație a acestei probleme este verificarea dacă un număr face parte dintr-un șir Fibonacci. Pentru a rezolva acest aspect introduc funcția _fFibonacciIS() cu paramentrul N, în care N este oricare număr natural pe care doresc să-l testez.

=LAMBDA(n; LET(_n; n; sir; _fFibonacciSir(_n+1); IF(ISNUMBER(MATCH(_n; sir;0)); TRUE; FALSE)))

Această funcție returnează valorile TRUE sau FALSE și reutilizează funcția _fFibonacciSir() pentru a calcula secvențele lui N. construcția _n1+1 din parametrul funcției este pentru a corecta problemele numerelor mici: 0, 1. În rezolvarea problemei 0 nu este considerat parte a acestei secvențe, chiar dacă în realitate el este primul număr. În versiunile viitoare voi aduce corecții dar în rezolvarea problemei am nevoie ca 0 să nu fie luat în seamă.

Un alt aspect important în aceste șiruri este raportul sau numărul de aur denumit φ (phi). Acest raport este întâlnit frecvent în lumea care ne înconjoară. Valoarea lui după al 14 element al șirului este 1,61803.

Problema FibFrog sau Salturile Fibonacci prin matrice

Fără a insista pe idioțeniile politice care spamează rețelele sociale, matricile în Excel au o putere deosebită de calcul vectorial și reprezintă o cale elegantă de a rezolva diferite tipuri de probleme.

FibFrog este o problemă care combină elemente din teoria numerelor (șirul Fibonacci) și grafuri. Scopul este să determini numărul minim de sărituri pe care o broască trebuie să le facă pentru a traversa un râu reprezentat de o serie de frunze și apă. Avem un șir binar A (de exemplu, [0, 1, 0, 0, 0, 1, 0]), unde: 1 reprezintă o frunză și 0 reprezintă apă. Broasca poate sări doar pe frunze (pe pozițiile marcate cu 1).

Dificultatea problemei este dată de restricția că lungimile săriturilor sunt restricționate la valor care aparțin șirului Fibonacci (F), adică {1, 2, 3, 5, 8, ...}.

Broasca începe la poziția -1 (deci înainte de prima frunză) și trebuie să ajungă după ultima poziție a șirului (pe N, unde N este lungimea șirului). Obiectivul principal este calcularea numărului minim de sărituri necesare pentru a traversa complet șirul de frunze și apă.

Dacă broasca nu poate traversa folosind sărituri din șirul Fibonacci, rezultatul trebuie să fie -1. Pentru a înțelege mai bine problema, cele mai bune explicații le-am găsit în sursa de mai jos.

Reprezentare grafică, captură video Youtube.

Sursa: Captură video Youtube: Fibonacci Frog Jump in Python and C++ Codility Coding Interview

Rezolvarea problemei în Excel pas cu pas.

Rezolvare problema FigFrog pas cu pas.

În B4 am descompus șirul dat în B2 cu funcția: =–TEXTSPLIT(B1;;”,”) apoi în A4 am calculat secvența de poziții a fiecărei frunze cu start de la 0: =SEQUENCE(ROWS(B4#);;0)

În D4 am calculat secvența de numere corespondent pozițiilor din A4 prin reutilizarea funcției _fBibonacciSir() definită anterior. M-am raportat la numărul maxim de poziții și am filtrat doar numerele care răspund criteriului: =LET(fib; _fFibonacciSir(MAX(A4#)); FILTER(fib; fib<=MAX(A4#)))

În E4 am calculat poziția frunzelor prin filtrarea vectorului Poz din A4 cu valorile 1 de pe vectorul A din B4. Ca să răspund cerințelor problemei, am adugat valoarea -1 ca fiind malul de start și valoarea maximă din poziții ca fiind malul destinație. =VSTACK(-1;FILTER(A4#;B4#=1);MAX(A4#)+1). În VSTACK() am adăugat 3 termen: valoarea -1, valorile filtrate din poziții și maxim poziții +1.

Cheia problemei este în H3 unde am proiectat o matrice RxC în care antet de coloane și linii sunt valorile frunzelor rezultate în E4. Formula utilizată este:

=LET(arr; E4#; _rows; ROWS(arr);
     diff; MAKEARRAY(_rows;_rows; LAMBDA(r;c; IF(c>=r; "";INDEX(arr;r)-INDEX(arr;c))));
     fScanCol; LAMBDA(c; MAP(c; LAMBDA(v; IF(_fFibonacciIS(v); v; ""))));
     fin; VSTACK(HSTACK(""; TRANSPOSE(arr));HSTACK(arr; fScanCol(diff)));
fin)

în care un rol deosebit îl are funcția recursivă fScanCol care apelează funcția creată anteriror: _fFibonacciIS(). Rolul său este de a păsta în matrice doar valorile din șirul Fibonacci.

Variabila diff este utilizată pentru a genera matricea ințială prin care scad valorile corespondente din vectorul arr pe toate combinațiile posibile. Ca să pot afișa antetele matricei (linii și coloane) am folosit o combinație de VSTACK() cu HSTACK().

A doua cheie este în H13 unde am extras toate combinațiile optime de salturi.

=LET(tab;H3#;_hr;CHOOSEROWS(tab;1);_hc;CHOOSECOLS(tab;1);
     tabi;SCAN(0;_hc; LAMBDA(a;v;LET(colc;XMATCH(v;_hr;0);
                                 poz;XMATCH(1;--ISNUMBER(CHOOSECOLS(tab;colc));0;-1);
                                 valc;INDEX(_hr;poz);
                                 return;CONCAT(v;";";valc);
                                 return)));
     valori;DROP(DROP(tabi;1);-1);
     splited; --TEXTSPLIT(TEXTJOIN("|";;valori);";";"|");
     splited)

Chiar dacă pare complicată, formula nu face decât să aducă valorile din antetul de linie și coloană specifice valorilor rezultat de pe fiecare coloană. Cheia este valoarea -1 din variabila poz care caută valoarea specifică de jos în sus pe vector-ul _hc care este de fapt prima coloană din matrice. colc este un artificiu care rulează scan-ul în matrice de fapt, coloană cu coloană. Nu aveam cum să rulez funcția BYCOL() pentru că nu o pot integra în SCAN(). Ca să păstrez doar pozițiile în forma start;final am utilizat două funcții DROP() prin care am eliminat prima și ultima linie din rezultat. Ca să pot vedea valorile tabelar am implemententat variabila splited care folosește artificiul de splitare linie cu linie.

Rezultatul final al funcției din H13 este identic cu cel din K13, unde am făcut de fapt reunificarea pentru a putea parcurge aceste valori cu scopul de a le extrage pe cele care îndeplinesc criteriul cerut.

Aparent cea mai grea chestie a fost să găsesc calea de a scoate doar perechile corecte de salturi. Pentru asta am încercat diferite abordări dar în final am ajuns tot la un SCAN() pe care l-am implementat în N13:

=SCAN(""; K13#; LAMBDA(a;v; IFERROR(IF(AND(a=""; ISNUMBER(TAKE(--TEXTSPLIT(v;";");;-1)));v; IF(TAKE(--TEXTSPLIT(v;";");;1)=TAKE(--TEXTSPLIT(a;";");;-1);v;a));-1)))

În această formulă parcurg vectorul K13# și descompun fiecare valoare F1-F2 pentru a o compara cu cele anterioare. Acumulatorul (a) este reprezentat permanent de combinația câștigătoare anterioară. Dacă valoarea de pe prima combinație nu este un număr atunci rezultatul funcției este -1 așa cum cere problema.

Toate funcțiile și calculele intermediare integrate vor duce la formula finală:

=LET(sir; B1; _A; --TEXTSPLIT(sir;;","); poz; SEQUENCE(ROWS(_A);;0);

     fReqFS; LAMBDA(n; DROP((((1 + SQRT(5)) / 2) ^ SEQUENCE(n) - ((1 - SQRT(5)) / 2) ^ SEQUENCE(n)) / SQRT(5); 1));
     fReqFIS; LAMBDA(n; LET(_n; n; sir; fReqFS(_n+1); IF(ISNUMBER(MATCH(_n; sir;0)); TRUE; FALSE)));

     fibo; LET(fib; fReqFS(MAX(poz)); FILTER(fib; fib<=MAX(poz)));

frunze; VSTACK(-1;FILTER(poz;_A=1);MAX(poz)+1);
matrix; LET(arr; frunze; _rows; ROWS(arr);
     diff; MAKEARRAY(_rows;_rows; LAMBDA(r;c; IF(c>=r; "";INDEX(arr;r)-INDEX(arr;c))));
     fScanCol; LAMBDA(c; MAP(c; LAMBDA(v; IF(fReqFIS(v); v; ""))));
     fin; VSTACK(HSTACK(""; TRANSPOSE(arr));HSTACK(arr; fScanCol(diff)));
fin);

perechi; LET(tab;matrix;_hr;CHOOSEROWS(tab;1);_hc;CHOOSECOLS(tab;1);
     tabi;SCAN(0;_hc; LAMBDA(a;v;LET(colc;XMATCH(v;_hr;0);
                                 poz;XMATCH(1;--ISNUMBER(CHOOSECOLS(tab;colc));0;-1);
                                 valc;INDEX(_hr;poz);
                                 return;CONCAT(v;";";valc);
                                 return)));
     valori;DROP(DROP(tabi;1);-1);

     valori);

pok; SCAN(""; perechi; LAMBDA(a;v; IFERROR(IF(AND(a=""; ISNUMBER(TAKE(--TEXTSPLIT(v;";");;-1)));v; IF(TAKE(--TEXTSPLIT(v;";");;1)=TAKE(--TEXTSPLIT(a;";");;-1);v;a));-1)));
unice; UNIQUE(pok);
"Nr perechi: " & ROWS(unice)& ": "&TEXTJOIN(" | ";;unice)
)

în care nu am mai folosit funcțiile definite la început ci le-am introdus ca recursive în această formulă pentru a evita erorile de a nu avea funcțiile definite / salvate.

Cam atât pentru această parte. Voi reveni cu un video pas cu pas pentru explicații suplimentare și cu partea a doua în viitor.

Aici varianta video pas cu pas.

Sper că v-a plăcut! :)

Blog la WordPress.com.

SUS ↑