Optimal Önbellekleme


14

Size bir dizi bellek isteği ve önbellek boyutu verilecektir. Herhangi bir önbellek değiştirme stratejisi altında mümkün olan en az sayıda önbellek kaybını döndürmelisiniz.

Optimal bir strateji, isterseniz Belady'nin algoritmasıdır .


Önbellek sistemi aşağıdaki gibi çalışır: Önbellek boş başlar. Bellek istekleri gelir. İstek önbellekte bir parça veri isterse, her şey yolunda demektir. Değilse, bir önbellek özledim. Bu noktada, daha sonra kullanılmak üzere önbelleğe istenen verileri ekleyebilirsiniz. Önbellek doluysa ve yeni veri eklemek istiyorsanız, daha önce önbellekte bulunan verileri çıkarmanız gerekir. Yalnızca önbellekte olmayan verileri asla ekleyemezsiniz.

Amacınız, belirli bir bellek isteği dizisi ve önbellek boyutu için mümkün olan minimum önbellek kaçış sayısını bulmaktır.


Size önbellek boyutu, pozitif bir tam sayı ve belirteçlerin listesi olan bellek isteği dizisi verilecektir. Bu jetonlar, en az 256 farklı jeton mümkün olduğu sürece (baytlar iyi, boolslar değil) istediğiniz tür jetonlar olabilir. Örneğin, ints, stringler, listeler gayet iyi. Gerekirse açıklama isteyin.


Test senaryoları:

3
[5, 0, 1, 2, 0, 3, 1, 2, 5, 2]

6

Bunu başaran bir değiştirme politikası için wikipedia'ya bakın .

2
[0, 1, 2, 0, 1, 0, 1]

3

2Önbelleğe eklemekten kaçının .

3
[0, 1, 2, 1, 4, 3, 1, 0, 2, 3, 4, 5, 0, 2, 3, 4]

9

Bunu başarmanın bir yolu , son kullanımından sonra asla tahliye etmemek 0ve mümkün olan en kısa zamanda 2tahliye etmektir 1.


Puanlama: Bu kod golfü. En az bayt kazanır.


Listenin en az 2 jeton içerdiğini varsayabilir miyiz?
Arnauld

@Arnauld hayır diyeceğim, ancak sadece 1 çözüm varsa, cevap her zaman 1'dir.
isaacg

Yanıtlar:


4

JavaScript (ES6), 128 bayt

Girişi alır (size)(list).

s=>a=>a.map((x,i)=>c.includes(x)?0:c[e++,[x,...c].map(m=(x,j)=>(k=[...a,x].indexOf(x,i+1))<m||(p=j,m=k)),i<s?i:p-1]=x,e=c=[])&&e

Çevrimiçi deneyin!

Yorumlananlar

Bu, Belady algoritmasının bir uygulamasıdır.

s => a =>                      // s = cache size; a[] = token list
  a.map((x, i) =>              // for each token x at position i in a[]:
    c.includes(x) ?            //   if x is currently stored in the cache:
      0                        //     do nothing
    :                          //   else:
      c[                       //     update the cache:
        e++,                   //       increment the number of errors (cache misses)
        [x, ...c]              //       we want to find which value among x and all current
                               //       cache values will be needed for the longest time in
                               //       the future (or not needed anymore at all)
        .map(m =               //       initialize m to a non-numeric value
                 (x, j) =>     //       for each x at position j in this array:
          ( k = [...a, x]      //         k = position of x in the array made of all values
            .indexOf(x, i + 1) //         of a[] followed by x, starting at i + 1
          ) < m                //         if it's greater than or equal to m, or m is
          || (p = j, m = k)    //         still non-numeric: set p to j and m to k
        ),                     //       end of inner map()
        i < s ?                //       if i is less than the cache size:
          i                    //         just fill the cache by using the next cache slot
        :                      //       else:
          p - 1                //         use the slot that was found above
                               //         special case: if p = 0, x was the best candidate
                               //         and we're going to store it at c[-1], which is
                               //         simply ignored (it will not trigger c.includes(x))
      ] = x,                   //     store x at this position
      e = c = []               //     start with e = [] (coerced to 0) and c = []
  ) && e                       // end of outer map; return e

4

Perl 5 , 193 bayt

sub g{
  my($i,$m,$s,@a,%c)=(-1,0,@_);
  for(@a){
    $i++;
    next if $c{$_}++ || ++$m && keys%c <= $s;
    my($x,$d);
    for $k (sort keys %c){  #find which to delete, the one furtherst away
      my $n=0;
      ++$n && /^$k$/ && last for @a[$i+1..$#a];
      ($x,$d)=($n,$k) if $n>$x
    }
    delete $c{$d}
  }
  $m
}

Çevrimiçi deneyin!

print g(3,  5, 0, 1, 2, 0, 3, 1, 2, 5, 2),"\n";                     # 6
print g(2,  0, 1, 2, 0, 1, 0, 1),"\n";                              # 3
print g(3,  0, 1, 2, 1, 4, 3, 1, 0, 2, 3, 4, 5, 0, 2, 3, 4),"\n";   # 9

Girintisiz 193 bayt, satırsonu, boşluk, yorum:

sub g{my($i,$m,$s,@a,%c)=(-1,0,@_);for(@a){$i++;next if$c{$_}++||++$m&&keys%c<=$s;my($x,$d);for$k(sort keys%c){my$n=0;++$n&&/^$k$/&&last for@a[$i+1..$#a];($x,$d)=($n,$k)if$n>$x}delete$c{$d}}$m}


1

Haskell , 82 bayt

f n|let(d:t)#c=1-sum[1|elem d c]+minimum[t#take n e|e<-scanr(:)(d:c)c];_#_=0=(#[])

Çevrimiçi deneyin!

açıklama

Kaba kuvvetle çalışır: tüm önbellek stratejileri denenir ve en iyi sonuç döndürülür.

f n            Define a function f on argument n (cache size) and a list (implicit).
 |let(d:t)#c=  Define binary helper function #.
               Arguments are list with head d (current data) and tail t (remaining data), and list c (cache).
 1-            It returns 1 minus
 sum[1|        1 if
 elem d c]+    d is in the cache, plus
 minimum[      minimum of
 t#            recursive calls to # with list t
 take n e|     and cache being the first n values of e, where
 e<-           e is drawn from
 scanr(:)  c]  the prefixes of c
 (d:c)         with d and c tacked to the end.
 ;_#_=0        If the first list is empty, return 0.
 =(#[])        f then calls # with the list argument and empty cache.

0

Perl 6 , 146 bayt

->\a,\b {$_=set();$!=0;for b.kv ->\i,\v {$_{v}&&next;++$!;vb[i^..*]||next;$_∖=.keys.max({(grep $_,:k,b[i^..*])[0]//Inf})if $_>=a;$_∪=v};$!}

Çevrimiçi deneyin!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.