Belirtildiği gibi, bu sorun daha yaygın olarak bilinen düzenleme mesafesi sorununa ( Levenshtein mesafesinin altında ) benzer. Aynı zamanda, örneğin Dinamik Zaman Çözgü mesafesiyle (son gereksiniminizdeki çoğaltma veya “kekemelik”) ortak özelliklere sahiptir.
Dinamik programlamaya doğru adımlar
Levenshtein mesafe ve dinamik zaman eşleştirme Mesafe çizgisinde özyinelemeli ayrışması ilk denemesi aşağıdaki (için gibi bir şey ve Y = y 1 ... y m ) ile, d ( x , y ) bir varlık ayarla
x = x1… Xny= y1… Ymd(x,y)
min⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪d(x,y1…ym−1)+1d(x,y2…ym)+1d(x,y1…ym/2)+1d(x1…xn/2,y)+1d(x1…xn,y)+1d(x1…xn−1,y1…ym−1)if y=y1…ym/2y1…ym/2if x=x1…xn/2x1…xn/2if yn=ym▻ Add letter at end▻ Add letter at beginning▻ Doubling▻ Halving▻ Deletion▻ Ignoring last elt.
Burada, son seçenek temel olarak FOOX'u BARX'e dönüştürmenin FOO'yu BAR'a dönüştürmeye eşdeğer olduğunu söylüyor. Bu, kekemelik (çoğaltma) efekti ve bir noktada silme işlemini elde etmek için “sonunda harf ekle” seçeneğini kullanabileceğiniz anlamına gelir. Sorun, otomatik bir eklemenizi sağlar olmasıdır keyfi dize ortasında karakterini de , muhtemelen istemediğiniz bir şey. (Bu “özdeş son öğeleri yoksaymak” keyfi konumlarda silme ve kekemelik elde etmenin standart yoludur. Her iki uçta eklemelere izin vermek biraz zor olsa da, keyfi eklemeleri yasaklar…
Bu arızayı işi tamamen yapmasa da dahil ettim, bir başkası onu bir şekilde “kurtarabilirse” ve aşağıda sezgisel çözümümde kullandığım için.
(Elbette, mesafenizi gerçekten tanımlayan böyle bir arıza elde edebiliyorsanız, sadece not eklemeniz gerekir ve bir çözümünüz olur. Ancak, sadece öneklerle çalışmadığınız için, Notunuz için sadece dizinleri kullanabileceğinizi düşünün; her çağrı için gerçek, değiştirilmiş dizeleri saklamanız gerekebilir; bu, dizeleriniz önemli boyutta olursa çok büyük olur.)
Sezgisel çözüm yolunda atılan adımlar
Daha kolay anlaşılabilen ve biraz daha az yer kullanabilen başka bir yaklaşım, algoritmasını (temel olarak, en iyi- ilk dal ve bağlı). Arama alanı doğrudan düzenleme işlemleriniz tarafından tanımlanır. Şimdi, büyük bir dize için, sen olurA∗A ∗herhangi bir karakteri silebileceğinizden (her bir potansiyel silme için size bir komşu vererek) veya herhangi bir karakteri çoğaltarak (yine size doğrusal sayıda komşu vererek) geniş bir mahalleye sahip olmanın yanı sıra her iki uçta da herhangi bir karakter ekleyebilir size alfabe boyutunun iki katına eşit sayıda komşu verin. (Sadece tam Unicode kullanmamanızı umuyoruz ;-) Böyle büyük bir fanout ile, çift yönlü veya bir akrabaA∗ kullanarak oldukça önemli bir hızlanma elde edebilirsiniz .
Hale getirmek için işi, size hedefe bir alt bağlı kalan mesafe için gerekiyordu. Burada açık bir seçim olup olmadığından emin değilim, ancak yapabileceğiniz şey, yukarıda verdiğim özyinelemeli ayrışmaya dayalı dinamik bir programlama çözümü uygulamaktır (yine dizeleriniz çok uzunsa olası alan sorunları ile). Bu ayrışma mesafenizi tam olarak hesaplamasa da , daha düşük bir sınır olması garanti edilir (çünkü daha izin vericidir), bu da sezgisel olarak çalışacağı anlamına gelir . (Ne kadar sıkı olacak, bilmiyorum, ama doğru olurdu.) Tabii ki, bağlı fonksiyonunuzun notu sırasında sınırın tüm hesaplamaları arasında paylaşılabilir.A ∗ A ∗A∗A∗A∗Çalıştırmak. (Orada bir zaman / mekan-ödünleşme.)
Yani…
Önerilen çözümümün verimliliği (1) dizelerinizin uzunluğuna ve (2) alfabenizin boyutuna biraz bağlı gibi görünüyor. İkisi de büyük değilse, işe yarayabilir. Yani:
- Özyinelemeli ayrıştırma ve dinamik programlamayı kullanarak (örneğin, kaydedilmiş, özyinelemeli işlev kullanarak) alt sınırınızı mesafenize uygulayın.
- Uygulamak (ya da iki yönlü Durum uzayında “hamle” ve dinamik programlama tabanlı alt bağlı olarak düzenleme operasyonları ile).A ∗A∗A∗
Ne kadar verimli olacağına dair hiçbir garanti veremem, ama doğru olmalı ve muhtemelen kaba kuvvetli bir çözümden çok daha iyi olurdu.
Başka bir şey yoksa, umarım bu size daha fazla araştırma için bazı fikirler verir.