Minimum Stack

A gyakorlaton láttuk, hogyan lehet egy minimum lekérdezését támogató vermet megalkotni. Ez egy olyan megoldás volt, ahol plusz $O(n)$ tárat használtunk fel. A továbbiakban megnézzük, hogyan lehet egy teljes plusz verem helyett egyetlen változóval, azaz plusz konstans tárral ugyanezt a logikát megvalósítani.

Egyetlen változóban fogjuk feljegyezni az aktuális minimumot, legyen ez $MinE$. Ez egy stack elem esetén ugyanaz, viszont nem csak push() műveletek után kell tudnunk megmondani a minimumot, hanem minden részveremre, így az az érdekes eset, hogy egyetlen változóval hogyan kezeljük azt, ha kivesszük az aktuális minimumot a veremből. Hogyan jegyezzük tehát meg, hogy ki volt a törölt elem alatt a minimum? A koncepció az, hogy ha egy új $x$ minimumot érkezik, helyette a $2x-MinE$ értéket rakjuk a verembe, így amikor törlünk, vissza tudjuk állítani az információt a maradék tömbre is. A műveletek a következőképpen működnek:

Push(x) : Az $x$ elemet a verem tetejére teszi.

  • Ha a verem üres, szúrjuk be $x$-et a verembe és legyen $MinE=x$.
  • Ha a verem nem üres hasonlítsuk össze $x$-et és $MinE$-t. Ekkor két eset lehetséges:
    • Ha $x\geq MinE$, csak szúrjuk be $x$-et a verembe és kész.
    • Ha $x<MinE$, szúrjuk be a $(2*x – MinE)$ értéket a verembe és legyen $MinE=x$. (Note: Vegyük észre, ilyenkor az aktális elemnél mindenképp egy kisebbet fogunk kapni!)

Pop() : Törli a verem tetején lévő értéket

  • Vegyük ki a legfelső elemet. Legyen ez $y$. Két eset lehetséges:
    • Ha $y\geq MinE$, nincs dolgunk, továbbra is $MinE$ a minimum az érték pedig a tényleges kivett érték.
    • Ha $y < MinE$, akkor az aktuális minimumot töröljük és az alattalévők minimumát a $(2*MinE – y)$ értékből kapjuk vissza. Tehát jegyezzük fel az aktuális minimumot, mivel a jelenlegi érték helyett azt kell visszaadjuk, majd legyen $MinE = 2*MinE – y$.

Technikai részletek:

  • A részminimumok sosem az eredeti értékükkel tárolódnak a veremben
  • Viszont az aktuális minimumot mindig számon tartjuk a $MinE$ változóban, így $O(1)$ idő alatt vissza tudjuk adni.
  • A Pop(), Push(x) és Min() műveletek továbbra is konstans időben elvégezhetőek
  • A felhasznált plusz tár csupán egyetlen változó, ami $O(1)$

Példa:

Push(x)
Beszúrt szám Aktuálus veremtartalom $MinE$
3 3 3
5 5 3 3
2 1 5 3 2
1 0 1 5 3 1
1 1 0 1 5 3 1
-1 -3 1 0 1 5 3 -1
m
  Működése:
  A verem üres, beszúrjuk a verembe és felveszi az értékét $MinE$ is
  Az $5$ nagyobb, mint $3$, így nincs extra művelet.
  A $2 < 3$: szúrjuk be a $2*2-3 = 1$ elemet, és $MinE$ értékét állítsuk az aktuális minimumra
  Az $1< 2$: szúrjuk be a $2*1 - 2 = 0$ elemet, és $MinE=1$
  $1=1$, nincs más dolgunk, mint beszúrni
  $-1<1$, beszúrjuk a $2*-1-1=-3$ elemet és $MinE=-1$
 
 
 

 

Pop(x)
Kivett érték Eredeti érték Aktuálus veremtartalom $MinE$
- - -3 1 0 1 5 3 -1
-3 -1 1 0 1 5 3 1
1 1 0 1 5 3 1
0 1 1 5 3 2
1 2 5 3 3
5 5 3 3
m
Működése:
Az aktiális minimum -1
A kivett elem $-3<-1$. Visszaadni a $MinE$-t fogjuk, és $MinE$ új értéke $2*-1-(-3)=1$
A kivett elem $1=1$. Nincs dolgunk.
A kivett elem $0<1$. Visszaadni a $MinE$-t fogjuk, és $MinE$ új értéke $2*1-0=2$
A kivett elem $1<2$. Visszaadni a $MinE$-t fogjuk, és $MinE$ új értéke $2*2-1=3$
A kivett elem $5>3$, nincs dolgunk
tipus: