Dinamik programlama nedir? [kapalı]


276

Nedir dinamik programlama ?

Özyineleme, not, vb. Arasında ne fark vardır?

Üzerinde wikipedia makalesini okudum , ama hala gerçekten anlamıyorum.


1
CMU'dan özellikle yararlı bulduğum bir öğretici: mat.gsia.cmu.edu/classes/dynamic/dynamic.html Kesinlikle başkalarının önerdiği tüm kaynaklara ek olarak (diğer tüm kaynaklar, özel olarak CLR) ve Kleinberg, Tardos çok iyi!). Bu öğreticiyi sevmemin nedeni, gelişmiş kavramları oldukça yavaş bir şekilde tanıtmasıdır. Biraz eskimiş bir malzemedir, ancak burada sunulan kaynaklar listesine iyi bir ektir. Ayrıca Steven Skiena'nın sayfasına ve Dinamik Programlama derslerine de göz atın: cs.sunysb.edu/~algorith/video-lectures http:
Edmon

11
Her zaman "Dinamik Programlama" kafa karıştırıcı bir terim buldum - "Dinamik" statik olmayan, ancak "Statik Programlama" nedir? Ve "... Programlama" akla getiriyor ki "Nesne Odaklı Programlama" ve "Fonksiyonel Programlama", DP'nin bir programlama paradigması olduğunu düşündürüyor. Gerçekten daha iyi bir ismim yok (belki "Dinamik Algoritmalar"?) Ama buna takılmak çok kötü.
dimo414

3
@ dimo414 Buradaki "programlama" daha çok, matematiksel optimizasyon yöntemleri sınıfına giren "doğrusal programlama" ile ilgilidir. Diğer matematiksel programlama yöntemlerinin listesi için Matematiksel optimizasyon makalesine bakın .
syockit

1
@ dimo414 Bu bağlamda "programlama", bilgisayar kodu yazmak için değil, tablo şeklinde bir yöntemi ifade eder. - Coreman
user2618142

Cs.stackexchange.com/questions/59797/… ' de açıklanan otobüs bileti maliyetini en aza indirme sorunu en iyi dinamik programlamada çözülür.
truthadjustr

Yanıtlar:


210

Dinamik programlama, gelecekteki bir sorunu çözmeyi kolaylaştırmak için geçmiş bilgisini kullandığınız zamandır.

Bunun iyi bir örneği n = 1,000,002 için Fibonacci dizisini çözmektir.

Bu çok uzun bir süreç olacak, ama n = 1,000,000 ve n = 1,000,001 için sonuçları verirsem? Aniden sorun daha kolay yönetilebilir hale geldi.

Dinamik programlama, string düzenleme problemi gibi string problemlerinde çok kullanılır. Sorunun bir alt kümesini / gruplarını çözersiniz ve sonra bu bilgileri daha zor orijinal sorunu çözmek için kullanırsınız.

Dinamik programlama ile, sonuçlarınızı genellikle bir tür tabloda saklarsınız. Bir sorunun cevabına ihtiyacınız olduğunda, tabloya bakın ve bunun ne olduğunu zaten bilip bilmediğinize bakın. Değilse, tablonuzdaki verileri kendinize cevaba doğru bir atlama taşı vermek için kullanırsınız.

Cormen Algorithms kitabının dinamik programlama hakkında harika bir bölümü var. VE Google Kitaplar'da ücretsiz! Buradan kontrol edin .


50
Yine de memoizasyonu tarif etmediniz mi?
dreadwail

31
Memoized işlevi / yöntemi özyinelemeli bir olduğunda, memoization bir dinamik programlama biçimi olduğunu söyleyebilirim.
Daniel Huckstep

6
İyi cevap, sadece optimal alt yapıdan bahsederdi (örneğin, A'dan B'ye en kısa yol boyunca herhangi bir yolun her alt kümesi, üçgen eşitsizliğini gözlemleyen bir mesafe metriği varsayarak 2 uç nokta arasındaki en kısa yoldur).
Shea

5
"Daha kolay" değil, daha hızlı diyebilirim. Yaygın bir yanlış anlama, dp'nin saf algoritmaların yapamadığı sorunları çözmesidir ve durum böyle değildir. İşlevsellik değil, performans meselesidir.
andandandand

6
Not kullanarak dinamik programlama sorunları yukarıdan aşağıya bir şekilde çözülebilir. yani, son değeri hesaplamak için işlevi çağırmak ve bu işlev, alt problemleri çözmek için özyinelemeli olarak çağırır. Onsuz, dinamik programlama sorunları ancak aşağıdan yukarıya doğru çözülebilir.
Pranav

175

Dinamik programlama, özyinelemeli algoritmada aynı alt sorunun birden çok kez hesaplanmasını önlemek için kullanılan bir tekniktir.

Let Fibonacci sayılarının basit örneği inceleyelim: n bularak inci tanımlanan Fibonacci sayı

F n = F n-1 + F n-2 ve F 0 = 0, F 1 = 1

özyineleme

Bunu yapmanın bariz yolu özyinelemelidir:

def fibonacci(n):
    if n == 0:
        return 0
    if n == 1:
        return 1

    return fibonacci(n - 1) + fibonacci(n - 2)

Dinamik program

  • Yukarıdan Aşağıya - Memoization

Özyineleme çok sayıda gereksiz hesaplama yapar, çünkü belirli bir Fibonacci sayısı birden çok kez hesaplanır. Bunu iyileştirmenin kolay bir yolu, sonuçları önbelleğe almaktır:

cache = {}

def fibonacci(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    if n in cache:
        return cache[n]

    cache[n] = fibonacci(n - 1) + fibonacci(n - 2)

    return cache[n]
  • Altüst

Bunu yapmanın daha iyi bir yolu, sonuçları doğru sırayla değerlendirerek özyineleme işleminden hep birlikte kurtulmaktır:

cache = {}

def fibonacci(n):
    cache[0] = 0
    cache[1] = 1

    for i in range(2, n + 1):
        cache[i] = cache[i - 1] +  cache[i - 2]

    return cache[n]

Sabit alanı bile kullanabilir ve yol boyunca sadece gerekli kısmi sonuçları saklayabiliriz:

def fibonacci(n):
  fi_minus_2 = 0
  fi_minus_1 = 1

  for i in range(2, n + 1):
      fi = fi_minus_1 + fi_minus_2
      fi_minus_1, fi_minus_2 = fi, fi_minus_1

  return fi
  • Dinamik programlama nasıl uygulanır?

    1. Problemdeki özyinelemeyi bulun.
    2. Yukarıdan aşağıya: yeniden hesaplamak zorunda kalmamak için her alt sorunun yanıtını bir tabloda saklayın.
    3. Aşağıdan yukarıya: Gerektiğinde kısmi sonuçların elde edilebilmesi için sonuçları değerlendirmek üzere doğru sırayı bulun.

Dinamik programlama genellikle dizeler, ağaçlar veya tamsayı dizileri gibi doğal olarak soldan sağa bir sıraya sahip problemler için çalışır. Saf özyinelemeli algoritma aynı alt sorunu birden çok kez hesaplamazsa, dinamik programlama yardımcı olmaz.

Mantığı anlamanıza yardımcı olacak bir sorun koleksiyonu yaptım: https://github.com/tristanguigue/dynamic-programing


3
Bu harika bir cevap ve Github'daki problem koleksiyonu da çok faydalı. Teşekkürler!
p4sh4

Sadece bir şeyleri açıklamak için meraktan - sizin fikrinize göre, bir yineleme ilişkisi ve hatırlama kullanarak yinelemeli bir uygulama dinamik programlama mı?
Codor

Açıklama için teşekkürler. Aşağıdan yukarıya eksik bir durum var mı: if n in cacheyukarıdan aşağıya örnekte olduğu gibi veya bir şey eksik mi?
DavidC

Bundan sonra, her bir yinelemede hesaplanan değerlerin sonraki yinelemelerde kullanıldığı herhangi bir döngünün dinamik programlamaya örnek olduğunu doğru anladım mı?
Alexey

Yukarıdan aşağıya ve aşağıdan yukarıya özel durumlar da dahil olmak üzere verdiğiniz yorum için herhangi bir referans verebilir misiniz?
Alexey

37

Memoization, bir işlev çağrısının önceki sonuçlarını kaydettiğiniz zamandır (gerçek bir işlev, aynı girdiler verildiğinde her zaman aynı şeyi döndürür). Sonuçlar saklanmadan önce algoritmik karmaşıklık için fark yaratmaz.

Özyineleme, genellikle daha küçük bir veri kümesiyle kendini çağıran bir işlevin yöntemidir. Yinelemeli işlevlerin çoğu benzer yinelemeli işlevlere dönüştürülebildiğinden, bu algoritmik karmaşıklık için de bir fark yaratmaz.

Dinamik programlama, daha kolay çözülebilen alt problemleri çözme ve bunun cevabını oluşturma sürecidir. Çoğu DP algoritması, bir Açgözlü algoritması (varsa) ve bir üstel (tüm olasılıkları numaralandırın ve en iyisini bulun) algoritması arasındaki çalışma sürelerinde olacaktır.

  • DP algoritmaları özyineleme ile uygulanabilir, ancak bunların olması gerekmez.
  • DP algoritmaları her bir alt problem sadece bir kez çözüldüğünden (veya çağrılan "çöz" işlevi) hatırlama ile hızlandırılamaz.

Çok açık söylemek gerekirse. Keşke algoritma eğitmenleri bunu iyi açıklayabilseydi.
Kelly

21

Algoritmanızın çalışma süresini kısaltan bir optimizasyonu.

Açgözlü Algoritma genellikle saf denir , aynı veri kümesi üzerinde birden çok kez çalışabileceğinden, Dinamik Programlama, nihai çözümü oluşturmaya yardımcı olması için saklanması gereken kısmi sonuçların daha derin bir şekilde anlaşılmasıyla bu tuzaktan kaçınır.

Basit bir örnek, bir ağaca veya grafiğe yalnızca çözüme katkıda bulunacak düğümlerden geçerek veya şimdiye kadar bulduğunuz çözümleri bir tabloya yerleştirerek aynı düğümleri tekrar tekrar gezmekten kaçınmaktır.

UVA'nın çevrimiçi hakimlerinden dinamik programlama için uygun bir sorun örneği: Edit Steps Ladder.

Programlama Zorlukları kitabından alınan bu sorunun analizinin önemli bir kısmını hızlı bir şekilde bilgilendireceğim, bir göz atmanızı öneririm.

Bu soruna iyi bakın, bize iki dizenin ne kadar uzak olduğunu söyleyen bir maliyet fonksiyonu tanımlarsak, iki tür üç doğal değişiklik türünü göz önünde bulundururuz:

Değiştirme - "s" deseninden tek bir karakteri "t" metninde "çekim" i "nokta" olarak değiştirmek gibi farklı bir karakterle değiştirin.

Ekleme - "t" metniyle eşleşmesine yardımcı olması için, "ago" metnini "agog" olarak değiştirmek gibi "s" desenine tek bir karakter ekleyin.

Silme - "t" metniyle eşleşmesine yardımcı olması için "s" harfinden tek bir karakteri silerek "saat" i "bizim" olarak değiştirme.

Bu işlemlerin her birini bir adım maliyet olarak ayarladığımızda, iki dize arasındaki düzenleme mesafesini tanımlarız. Peki bunu nasıl hesaplıyoruz?

Dizideki son karakterin eşleştirilmesi, ikame edilmesi, eklenmesi veya silinmesi gerektiği gözlemini kullanarak özyinelemeli bir algoritma tanımlayabiliriz. Son düzenleme işlemindeki karakterlerin kesilmesi, bir çift işlemin bir çift daha küçük dize bırakmasını sağlar. İ ve j sırasıyla ve t'nin ilgili önekinin son karakteri olsun. son işlemden sonra, bir eşleşme / değiştirme, ekleme veya silme işleminden sonra dizeye karşılık gelen üç çift daha kısa dize vardır. Üç çift daha küçük dizeyi düzenleme maliyetini biliyorsak, hangi seçeneğin en iyi çözüme yol açacağına karar verebilir ve bu seçeneği buna göre seçebiliriz. Bu maliyeti, özyineleme olan harika şeyle öğrenebiliriz:

#define MATCH 0 /* enumerated type symbol for match */
#define INSERT 1 /* enumerated type symbol for insert */
#define DELETE 2 /* enumerated type symbol for delete */


int string_compare(char *s, char *t, int i, int j)

{

    int k; /* counter */
    int opt[3]; /* cost of the three options */
    int lowest_cost; /* lowest cost */
    if (i == 0) return(j * indel(’ ’));
    if (j == 0) return(i * indel(’ ’));
    opt[MATCH] = string_compare(s,t,i-1,j-1) +
      match(s[i],t[j]);
    opt[INSERT] = string_compare(s,t,i,j-1) +
      indel(t[j]);
    opt[DELETE] = string_compare(s,t,i-1,j) +
      indel(s[i]);
    lowest_cost = opt[MATCH];
    for (k=INSERT; k<=DELETE; k++)
    if (opt[k] < lowest_cost) lowest_cost = opt[k];
    return( lowest_cost );

}

Bu algoritma doğrudur, ancak imkansız bir şekilde yavaştır.

Bilgisayarımızda çalıştığımızda, iki 11 karakterli dizeyi karşılaştırmak birkaç saniye alır ve hesaplama hiçbir zaman daha uzun bir şeye asla inmez.

Algoritma neden bu kadar yavaş? Üstel zaman alır çünkü değerleri tekrar tekrar hesaplar. Dizideki her pozisyonda, özyineleme üç şekilde dallanır, yani en azından 3 ^ n oranında büyür - aslında, daha da hızlıdır, çünkü çağrıların çoğu her ikisini de değil, iki endeksten sadece birini azaltır.

Peki algoritmayı nasıl pratik hale getirebiliriz? Önemli gözlem, bu özyinelemeli çağrıların çoğunun daha önce hesaplanmış olan şeyleri hesaplamasıdır. Nasıl bilebiliriz? Sadece | s | · | T | olası benzersiz özyinelemeli çağrılar, çünkü özyinelemeli çağrıların parametreleri olarak işlev görecek çok farklı (i, j) çiftleri vardır.

Bu (i, j) çiftlerinin her birinin değerlerini bir tabloda depolayarak, bunları yeniden hesaplamaktan kaçınabilir ve sadece gerektiğinde ararız.

Tablo iki boyutlu bir matris m olup burada | s | · | t | hücreleri, bu alt problemin en uygun çözümünün maliyetini ve bu konuma nasıl geldiğimizi açıklayan bir üst işaretçiyi içerir:

typedef struct {
int cost; /* cost of reaching this cell */
int parent; /* parent cell */
} cell;

cell m[MAXLEN+1][MAXLEN+1]; /* dynamic programming table */

Dinamik programlama sürümü özyinelemeli sürümden üç farklılığa sahiptir.

İlk olarak, ara değerlerini yinelemeli çağrılar yerine tablo aramasını kullanarak alır.

** İkinci olarak, ** her hücrenin üst alanını güncelleyerek düzenleme sırasını daha sonra yeniden oluşturmamızı sağlayacaktır.

** Üçüncüsü, Üçüncüsü, cell()sadece m [| s |] [| t |] .cost döndürmek yerine daha genel bir hedef fonksiyonu kullanılarak gerçekleştirilmiştir. Bu, bu rutini daha geniş bir sorun sınıfına uygulamamızı sağlayacaktır.

Burada, en uygun kısmi sonuçları toplamak için gerekenlerin çok özel bir analizi, çözümü “dinamik” yapan şeydir.

İşte aynı soruna alternatif, tam bir çözüm. Ayrıca, yürütülmesi farklı olsa da "dinamik" bir programdır. UVA'nın çevrimiçi hakemine göndererek çözümün ne kadar verimli olduğunu kontrol etmenizi öneririm. Böyle ağır bir sorunun nasıl bu kadar verimli bir şekilde ele alındığını şaşırtıcı buluyorum.


Dinamik programlama için depolama gerçekten gerekli mi? Herhangi bir çalışma atlama algoritmayı dinamik olarak nitelendirmez mi?
Nthalk

Sen sahip optimum toplamak için adım adım bir algoritma "dinamik" hale getirmek için sonuçlar. Dinamik Programlama, Bellman'ın OR'deki çalışmasından kaynaklanır, eğer "herhangi bir kelimeyi atlamanın dinamik programlamadır" derseniz, herhangi bir arama sezgiselliği dinamik programlama olacağı için terimi devalüe edersiniz. en.wikipedia.org/wiki/Dynamic_programming
andandandave

12

Dinamik programlamanın temel bitleri "örtüşen alt problemler" ve "optimal alt yapı" dır. Bir problemin bu özellikleri, optimal bir çözümün, alt problemlerine en uygun çözümlerden oluştuğu anlamına gelir. Örneğin, en kısa yol problemleri en uygun alt yapıyı gösterir. A'dan C'ye en kısa yol, A'dan bazı B düğümüne en kısa yoldur, ardından bu düğümden B'ye C en kısa yoldur.

Daha ayrıntılı olarak, en kısa yol problemini çözmek için:

  • başlangıç ​​düğümünden ona değen her düğüme kadar olan mesafeleri bulun (A'dan B'ye ve C'den diyelim)
  • bu düğümlerden kendilerine dokunan düğümlere olan mesafeleri bulun (B'den D'ye ve E'den C'ye ve E'den F'ye)
  • şimdi A'dan E'ye en kısa yolu biliyoruz: ziyaret ettiğimiz bazı düğümler için (B veya C) Ax ve xE'nin en kısa toplamıdır
  • son hedef düğüme ulaşana kadar bu işlemi tekrarlayın

Aşağıdan yukarıya çalıştığımızdan, bunları kullanma zamanı geldiğinde, alt problemlere onları hatırlayarak çözümlerimiz var.

Unutmayın, dinamik programlama problemleri hem örtüşen alt problemlere hem de optimal altyapıya sahip olmalıdır. Fibonacci dizisinin oluşturulması dinamik bir programlama problemi değildir; üst üste binen alt problemlere sahip olduğu için, ancak optimal bir altyapıya sahip olmadığı için (not optimizasyon problemi olmadığı için) hatırlatma kullanır.


1
IMHO, dinamik programlama açısından mantıklı olan tek cevap bu. İnsanların DP'yi Fibonacci sayılarını (neredeyse hiç alakalı) kullanarak açıklamaya başladığından beri merak ediyorum.
Terry Li

@TerryLi, "Mantıklı" olabilir, ancak anlaşılması kolay değildir. Fibonacci sayı problemi bilinmektedir ve anlaşılması kolaydır.
Ajay

5

Dinamik program

Tanım

Dinamik programlama (DP), çakışan alt problemlerle ilgili problemleri çözmek için kullanılan genel bir algoritma tasarım tekniğidir. Bu teknik 1950'lerde Amerikalı matematikçi “Richard Bellman” tarafından icat edildi.

Anahtar fikir

Anahtar fikir, yeniden hesaplamayı önlemek için çakışan daha küçük alt sorunların cevaplarını kaydetmektir.

Dinamik Programlama Özellikleri

  • Bir örnek, daha küçük örneklerin çözümleri kullanılarak çözülür.
  • Daha küçük bir örneğe yönelik çözümlere birden çok kez ihtiyaç duyulabilir, bu nedenle sonuçlarını bir tabloda saklayın.
  • Böylece her küçük örnek sadece bir kez çözülür.
  • Zaman kazanmak için ek alan kullanılır.

4

Ayrıca Dinamik Programlama (belirli tür problemler için güçlü bir algoritma) konusunda çok yeniyim

En basit ifadeyle, dinamik programlamayı önceki bilgileri kullanarak özyinelemeli bir yaklaşım olarak düşünün

Önceki bilgi burada en önemli şeydir, Zaten sahip olduğunuz alt sorunların çözümünü takip edin.

Bunu düşünün, Wikipedia'dan dp için en temel örnek

Fibonacci dizisini bulma

function fib(n)   // naive implementation
    if n <=1 return n
    return fib(n − 1) + fib(n − 2)

İşlev çağrısını say n = 5 ile parçalayalım

fib(5)
fib(4) + fib(3)
(fib(3) + fib(2)) + (fib(2) + fib(1))
((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
(((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))

Özellikle, fib (2) sıfırdan üç kez hesaplandı. Daha büyük örneklerde, fib veya alt problemlerin daha birçok değeri yeniden hesaplanarak üstel bir zaman algoritmasına yol açar.

Şimdi, zaten bir veri yapısında öğrendim değerini saklayarak denemek sağlayan bir say Haritası

var m := map(0 → 0, 1 → 1)
function fib(n)
    if key n is not in map m 
        m[n] := fib(n − 1) + fib(n − 2)
    return m[n]

Burada, eğer zaten yoksa, alt sorunların çözümünü haritaya kaydediyoruz. Daha önce hesaplamış olduğumuz değerleri kaydetme tekniği Memoization olarak adlandırılmıştır.

Sonunda, bir sorun için, önce durumları bulmaya çalışın (olası alt problemler ve önceki alt problemin çözümünü başkalarına da kullanabilmeniz için daha iyi özyineleme yaklaşımını düşünmeye çalışın).


Vikipedi'den düz soygun. Downvoted !!
solidak

3

Dinamik programlama, çakışan alt problemlerle ilgili problemleri çözmek için bir tekniktir. Dinamik bir programlama algoritması her alt problemi sadece bir kez çözer ve ardından cevabını bir tabloya (dizi) kaydeder. Alt sorunla her karşılaşıldığında cevabı yeniden hesaplama işinden kaçınmak. Dinamik programlamanın altında yatan fikir şudur: Aynı şeyleri, genellikle alt sorunların bilinen sonuçlarının bir tablosunu tutarak iki kez hesaplamaktan kaçının.

Dinamik bir programlama algoritmasının geliştirilmesindeki yedi adım aşağıdaki gibidir:

  1. Sorunun bir örneğine çözüm veren özyinelemeli bir özellik oluşturun.
  2. Özyinelemeli özelliğe göre özyinelemeli algoritma geliştirme
  3. Yinelenen çağrılarda sorunun aynı örneğinin tekrar çözülüp çözülmediğine bakın
  4. Belleğe alınan bir özyinelemeli algoritma geliştirme
  5. Verileri hafızaya kaydetme şekline bakın
  6. Belleğe alınan özyinelemeli algoritmayı yinelemeli algoritmaya dönüştürme
  7. Depolamayı gerektiği gibi kullanarak yinelemeli algoritmayı optimize edin (depolama optimizasyonu)

6. Convert the memoized recursive algorithm into iterative algorithmzorunlu adım? Bu son şeklinin özyinelemesiz olduğu anlamına mı gelir?
truthadjustr

zorunlu değil, isteğe bağlı
Adnan Qureshi

Amaç, yinelemeli bir çözüm, yapılan her özyinelemeli çağrı için bir işlev yığını oluşturulmasını kaydettiğinden, bellekte veri depolamak için kullanılan özyinelemeli algoritmanın yerini bir yineleme ile değiştirmektir.
David C. Rankin

1

kısaca özyineleme notlama ve Dinamik programlama arasındaki fark

Adından da anlaşılacağı gibi dinamik programlama, bir sonraki yeni çözümü dinamik olarak oluşturmak için önceki hesaplanan değeri kullanıyor

Dinamik programlama nasıl uygulanır: Çözümünüz en uygun altyapıya ve çakışan alt soruna dayanıyorsa, bu durumda daha önce hesaplanan değeri kullanmak yararlı olacaktır, böylece yeniden hesaplamanız gerekmez. Aşağıdan yukarıya yaklaşımdır. Bu durumda fib (n) 'yi hesaplamanız gerektiğini varsayalım, tek yapmanız gereken önceki hesaplanmış fib (n-1) ve fib (n-2) değerlerini eklemektir.

Özyineleme: Temelde, sorunu kolayca çözmek için daha küçük bir bölüme ayırırsınız, ancak daha önce diğer özyineleme çağrısında hesaplanmış aynı değere sahipsek, yeniden hesaplamayı önlemez.

Memoization: Eski hesaplanan özyineleme değerinin tabloya kaydedilmesi, önceki bir çağrı tarafından zaten hesaplanmışsa yeniden hesaplamayı önleyecek memoizasyon olarak bilinir, böylece herhangi bir değer bir kez hesaplanır. Hesaplamadan önce, bu değerin önceden hesaplanıp hesaplanmadığını kontrol ediyoruz, eğer daha önce hesaplanmışsa, aynı şeyi yeniden hesaplama yerine tablodan döndürüyoruz. Ayrıca yukarıdan aşağıya bir yaklaşımdır


-2

İşte basit bir piton kod örneği Recursive, Top-down,Bottom-up Fibonacci serisi için yaklaşım:

Özyinelemeli: O (2 n )

def fib_recursive(n):
    if n == 1 or n == 2:
        return 1
    else:
        return fib_recursive(n-1) + fib_recursive(n-2)


print(fib_recursive(40))

Yukarıdan aşağıya: O (n) Daha büyük giriş için verimli

def fib_memoize_or_top_down(n, mem):
    if mem[n] is not 0:
        return mem[n]
    else:
        mem[n] = fib_memoize_or_top_down(n-1, mem) + fib_memoize_or_top_down(n-2, mem)
        return mem[n]


n = 40
mem = [0] * (n+1)
mem[1] = 1
mem[2] = 1
print(fib_memoize_or_top_down(n, mem))

Aşağıdan yukarıya: O (n) Basitlik ve küçük giriş boyutları için

def fib_bottom_up(n):
    mem = [0] * (n+1)
    mem[1] = 1
    mem[2] = 1
    if n == 1 or n == 2:
        return 1

    for i in range(3, n+1):
        mem[i] = mem[i-1] + mem[i-2]

    return mem[n]


print(fib_bottom_up(40))

İlk durumda n ^ 2 çalışma süresi YOKTUR, zaman karmaşıklığı O (2 ^ n): stackoverflow.com/questions/360748/…
Sam

güncellendi teşekkürler. @Sam
0xAliHn
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.