Nearest smaller elements

This commit is contained in:
Antti H S Laaksonen 2017-01-03 02:06:48 +02:00
parent 7f443cd64e
commit 173e5e75dd
1 changed files with 61 additions and 57 deletions

View File

@ -413,41 +413,44 @@ to find \emph{three} numbers whose sum is $x$.
This problem can be solved in $O(n^2)$ time. This problem can be solved in $O(n^2)$ time.
Can you see how it is possible? Can you see how it is possible?
\section{Lähin pienempi edeltäjä} \section{Nearest smaller elements}
\index{lzhin pienempi edeltxjx@lähin pienempi edeltäjä} \index{nearest smaller elements}
Tasoitetun analyysin avulla arvioidaan usein Amortized analysis is often used for
tietorakenteeseen kohdistuvien operaatioiden määrää. estimating the number of operations
Algoritmin operaatiot voivat jakautua epätasaisesti performed for a data structure.
niin, että useimmat operaatiot tehdään tietyssä The operations may be distributed unevenly so
algoritmin vaiheessa, mutta operaatioiden that the most operations appear during a
yhteismäärä on kuitenkin rajoitettu. certain phase in the algorithm, but the total
number of the operations is limited.
Tarkastellaan esimerkkinä ongelmaa, As an example, let us consider a problem
jossa tehtävänä on etsiä kullekin taulukon where our task is to find for each element
alkiolle in an array the
\key{lähin pienempi edeltäjä} eli \key{nearest smaller element}, i.e.,
lähinnä oleva pienempi alkio taulukon alkuosassa. the nearest smaller element that precedes
On mahdollista, ettei tällaista alkiota ole olemassa, the element in the array.
jolloin algoritmin tulee huomata asia. It is possible that no such element exists,
Osoittautuu, että tehtävä on mahdollista ratkaista and the algorithm should notice this.
tehokkaasti ajassa $O(n)$ sopivan tietorakenteen avulla. It turns out that the problem can be efficiently solved
in $O(n)$ time using a suitable data structure.
Tehokas ratkaisu tehtävään on käydä An efficient solution for the problem is to
taulukko läpi alusta loppuun ja pitää samalla yllä ketjua, iterate through the array from the left to the right,
jonka ensimmäinen luku on käsiteltävä taulukon luku and maintain a chain of elements where the
ja jokainen seuraava luku on luvun lähin first element is the active element in the array
pienempi edeltäjä. and each following element is the nearest smaller
Jos ketjussa on vain yksi luku, element of the previous element.
käsiteltävällä luvulla ei ole pienempää edeltäjää. If the chain only contains one element,
Joka askeleella ketjun alusta poistetaan lukuja the active element doesn't have a nearest smaller element.
niin kauan, kunnes ketjun ensimmäinen luku on At each step, we remove elements from the chain
pienempi kuin käsiteltävä taulukon luku tai ketju on tyhjä. until the first element is smaller
Tämän jälkeen käsiteltävä luku lisätään ketjun alkuun. than the active element, or the chain is empty.
After this, the active element becomes the first element
in the chain.
Tarkastellaan esimerkkinä algoritmin toimintaa As an example, consider the following array:
seuraavassa taulukossa:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\draw (0,0) grid (8,1); \draw (0,0) grid (8,1);
@ -473,9 +476,11 @@ seuraavassa taulukossa:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Aluksi luvut 1, 3 ja 4 liittyvät ketjuun, koska jokainen luku on First, numbers 1, 3 and 4 are added to the chain
edellistä suurempi. Siis luvun 4 lähin pienempi edeltäjä on luku 3, because each element is larger than the previous element.
jonka lähin pienempi edeltäjä on puolestaan luku 1. Tilanne näyttää tältä: This means that the nearest smaller element of
number 4 is number 3 whose nearest smaller element
is number 1.
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\fill[color=lightgray] (2,0) rectangle (3,1); \fill[color=lightgray] (2,0) rectangle (3,1);
@ -505,9 +510,10 @@ jonka lähin pienempi edeltäjä on puolestaan luku 1. Tilanne näyttää tält
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Taulukon seuraava luku 2 on pienempi kuin ketjun kaksi ensimmäistä lukua 4 ja 3. The next number 2 is smaller than two first numbers in the chain.
Niinpä luvut 4 ja 3 poistetaan ketjusta, minkä jälkeen luku 2 Thus, numbers 4 and 3 are removed, and then number 2 becomes
lisätään ketjun alkuun. Sen lähin pienempi edeltäjä on luku 1: the first element in the chain.
Its nearest smaller element is number 1:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\fill[color=lightgray] (3,0) rectangle (4,1); \fill[color=lightgray] (3,0) rectangle (4,1);
@ -536,9 +542,9 @@ lisätään ketjun alkuun. Sen lähin pienempi edeltäjä on luku 1:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Seuraava luku 5 on suurempi kuin luku 2, After this, number 5 is larger than number 2,
joten se lisätään suoraan ketjun alkuun ja so it will be added to the chain and
sen lähin pienempi edeltäjä on luku 2: its nearest smaller element is number 2:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\fill[color=lightgray] (4,0) rectangle (5,1); \fill[color=lightgray] (4,0) rectangle (5,1);
@ -568,25 +574,23 @@ sen lähin pienempi edeltäjä on luku 2:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Algoritmi jatkaa samalla tavalla taulukon loppuun Algorithm continues in a similar way
ja selvittää jokaisen luvun lähimmän and finds out the nearest smaller element
pienemmän edeltäjän. for each number in the array.
Mutta kuinka tehokas algoritmi on? But how efficient is the algorithm?
Algoritmin tehokkuus riippuu siitä, The efficiency of the algorithm depends on
kauanko ketjun käsittelyyn kuluu aikaa yhteensä. the total time used for manipulating the chain.
Jos uusi luku on suurempi kuin ketjun ensimmäinen If an element is larger than the first
luku, se vain lisätään ketjun alkuun, element in the chain, it will only be inserted
mikä on tehokasta. to the beginning of the chain which is efficient.
Joskus taas ketjussa voi olla useita However, sometimes the chain can contain several
suurempia lukuja, joiden poistaminen vie aikaa. larger elements and it takes time to remove them.
Oleellista on kuitenkin, että jokainen Still, each element is added exactly once to the chain
taulukossa oleva luku liittyy and removed at most once.
tarkalleen kerran ketjuun ja poistuu Thus, each element causes $O(1)$ operations
korkeintaan kerran ketjusta. to the chain, and the total time complexity
Niinpä jokainen luku aiheuttaa $O(1)$ of the algorithm is $O(n)$.
ketjuun liittyvää operaatiota
ja algoritmin kokonaisaikavaativuus on $O(n)$.
\section{Liukuvan ikkunan minimi} \section{Liukuvan ikkunan minimi}