Ne elemanları maksimal kümesini bulmak için


14

Algoritmik bir sorunum var.

TnSTaSa|S|

Örneğin:

  1. Eğer = [1, 3, 4, 1, 3, 6], daha sonra olabilir [3, 3, 6] ya da [3, 4, 6] veya [4, 3, 6].TS
  2. İçinde = [7, 5, 1, 1, 7, 4], daha sonra [7, 5, 7, 4].TS

Bu özyinelemeli işlevi denedim.

function(T):
    if minimum(T) >= length(T): 
        return T
    else: 
        return function(T\minimum(T))

Yinelemeli olmayan bir algoritma var mı? (Özyinelemeli algoritmamı kontrol etmedim, bu yüzden bazı kusurları olabilir.)

Yanıtlar:


14

T'yi sıralayın. Sonra öğelerini alın T[i] >= i+1.

Örneğin sorted(T)=[6,4,3,3,1,1]. Ardından T[0] = 6 > 1, T[1] = 4 > 2, T[2] = 3 <= 3ve nihayet, T[3] = 3 < 4bu yüzden var S = [T[0], T[1], T[2]].


3
Bu, elbette, diğer çözümü özlüyor , ancak OP'nin tüm çözümler yerine herhangi bir çözüm aradığı anlaşılıyor . {6,3,3}
Rick Decker

2
Eleman sayısını doğru yapar. 3 elementli çözümlerimiz olduğunu biliyoruz ama 4 değil çözümlerimiz var; bu durumda elements 3 elementimiz var, bu yüzden çözüm için 3 tanesini seçebileceğimizi biliyoruz.
gnasher729

3
Doğruluk iddiasını takdir ediyorum.
Raphael

Sanırım muhtemelen bir introselect varyantı ile O (n) zamanında yapabilirsin.
user2357112 Monica

8

Benim yorumum aslen: Bu yakından akademik verimlilik değerlendirmesinde bir miktar yerde ilgilidir, Hirsh indeksi, daha iyi olarak bilinen -İçindekiler . Kısacası, bu yayın sayısı olarak tanımlanır tek her biri en az sahip olduğu şekilde yer alır alıntılar (büyük, örneğin ).hhhh

Sorununuzun farklı olmasının tek yolu, sadece kaç yayının kriteri karşıladığı değil, aynı zamanda atıf sayılarının ne olduğu ile de ilgilenmenizdir , ancak bu önemsiz bir değişikliktir. Veriler zaten orada, orijinal algoritma onu düşürüyor.

Genel olarak uygulanan hesaplama oldukça basittir ve Karolis Juodelė'nin cevabını kabul eder .

Güncelleme: Verilerinizin boyutuna ve karakterine bağlı olarak, verileri önemli bir noktanın üstünde ve altında filtreleyerek diziyi kısmen sıralayan yöntemleri keşfetmeye değer olabilir (quicksort akla gelir). Ardından, çok az veya çok fazla olup olmadığına bağlı olarak, pivotu ayarlayın ve onu içeren alt kümede yeniden yapın vb. Sen daha yüksek elemanları arasında bir sipariş gerekmez değil daha düşük olanlar arasında kesinlikle ve. Örneğin, tüm öğeleri değerine eşit veya daha büyük bulduktan ve bunların değerinden daha azını sonra, bu alt kümeye tekrar dokunmanıza gerek yoktur, sadece ekleyin. Bu, özyinelemenin kendine özgü özyinelemeyi kuyruk özyinelemesine dönüştürür ve böylece bir döngü olarak yeniden yazılabilir.hh1h1

Haskell'im biraz paslı ama bu yukarıda tarif ettiğim şeyi yapmalı ve işe yarıyor gibi görünüyor. Umarım bir dereceye kadar anlaşılabilir, daha fazla açıklama vermekten mutluluk duyuyorum.

-- just a utility function
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : merge xs ys

-- the actual implementation
topImpl :: [Int] -> [Int] -> [Int]
topImpl [] granted = granted
topImpl (x:xs) granted
  | x == (1 + lGreater + lGranted) = x : merge greater granted
  | x > (1 + lGreater + lGranted) = topImpl smaller (x : merge greater granted)
  | otherwise = topImpl greater granted
  where smaller = [y | y <- xs, y < x]
        greater = [y | y <- xs, y >= x]
        lGreater = length greater
        lGranted = length granted

-- starting point is: top of whole array, granted is empty
top :: [Int] -> [Int]
top arr = topImpl arr []

Fikir, grantedsonuca kesinlikle katılacağını bildiğiniz şeyleri toplamak ve daha fazla sıralamamaktır. Eğer uyum greaterile birlikte x, şanslıyız, aksi takdirde daha küçük bir alt kümeyle denememiz gerekir. (Pivot x, şu anda dikkate alınan alt listenin ilk öğesi olan şeydir.) En büyük öğeleri teker teker almanın önemli avantajının, bunu ortalama boyutta bloklar üzerinde yapmamız ve ihtiyacımız olmamasıdır. onları sıralamak için.remaining/2

Misal:

Setinizi alalım [1,3,4,1,3,6].

  1. x = 1, granted = [], greater = [3,4,1,3,6]. Ah, smallerilk adımda pivot çok küçük olduğunda (aslında boş olan çok küçük) patolojik bir duruma çarptık . Neyse ki bizim algo buna hazır. Yalnız atar xve tekrar dener greater.

  2. x = 3, granted = [], greater = [4,3,6]. Birlikte, bir uzunluk 4 dizisi oluştururlar, ancak bunu sadece aşağıdan 3 ile sınırladık, bu yüzden çok fazla. greaterTek başına tekrarlayın .

  3. x = 4, granted = [], greater = [6]. Bu, her biri elements 4 olmak üzere 2 öğeden oluşan bir dizi verir, daha fazlası için kullanmış olabiliriz. Bunu sakla ve tekrar et smaller = [3].

  4. x = 3, granted = [4,6], greater = []. Bu birlikte her biri 3 elemandan oluşan bir dizi gives 3 verir, böylece çözümümüz vardır [3,4,6]ve geri dönebiliriz. (Permütasyonun, girişin sırasına bağlı olarak değişebileceğini, ancak asla [3,3,6]veya [3,3,4]örneğiniz için daima mümkün olan en yüksek terimleri içereceğini unutmayın.)

(Btw. Özyinelemenin gerçekten de bir döngüye çöktüğünü unutmayın.) Karmaşıklık, birçok kaydedilmiş karşılaştırma nedeniyle hızlı sıralamadan biraz daha iyidir:

En iyi örnek (ör. [2,2,1,1,1,1]): tek bir adım, karşılaştırmaların1

Ortalama vaka:O(logn)O(n)

nO(n2)

Yukarıdaki kodda smallerihtiyaç duyup duymadığımızı hesaplamak gibi birkaç gereksiz karşılaştırma var , bunlar kolayca kaldırılabilir. (Tembel değerlendirmenin bununla ilgileneceğini düşünüyorum.)


6

Algoritmanızda yanlış bir şey yoktur ve elbette yinelemeli algoritmaların çoğu döngülere dönüştürülebilir, burada yinelemeli kodunuzun döngü sürümü:

function(T):
    while minimum(T) <= lenght(T):
         remove minimum(T) from T
    loop

6
Tüm özyinelemeli algoritmalar döngülere dönüştürülebilir. Sonuçta, bir Turing makinesi özyineleme hakkında hiçbir şey bilmiyor.
David Richerby

4

Yinelemeyi kullanmak için herhangi bir özyinelemeli algoritma yeniden yazılabilir. Sonuçta, bir Turing makinesi özyineleme hakkında hiçbir şey bilmiyor, ancak herhangi bir algoritmayı uygulayabiliyor. Prensip olarak, fonksiyon parametrelerinin değerlerini ve sahip olabileceği yerel değişkenleri hatırlamak için kendi yığın manipülasyon kodunuzu yazarak özyinelemeli fonksiyonunuzu yeniden yazabilirsiniz. Bu özel durumda, işleviniz özyinelemeli (özyinelemeli bir çağrı döndüğünde, çağrılan şey hemen geri döner), böylece yığını korumanıza bile gerek kalmaz.


3

Tüm dizinin sıralanmasına gerek olmadığından, kısmi bir yığın oluşturmak için bir min-yığın kullanın.

Verilen eşiği aşana kadar öğeleri açgözlü bir şekilde açmaya devam edin.


2
Burada da doğruluk fikrini takdir ediyorum.
Raphael
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.