Üç tamsayıyı bulmak için kaba kuvvet arama dışında verimli bir algoritma var mı?
Evet; Bunu O (n 2 ) zamanda çözebiliriz ! İlk olarak, sorununuzun P"hedef değer" ihtiyacını ortadan kaldıran, biraz farklı bir şekilde eşdeğer olarak ifade edilebileceğini düşünün :
Özgün sorun P: bir dizi Verilen Aait ntamsayılar ve bir hedef değer S, yürüyerek 3 tuple orada var yok Ao özetliyor S?
tadil edilmiş bir sorun P': bir dizi göz önüne alındığında Aarasında nbir 3-tuple orada halen mevcut, tam sayılar Asıfır olduğu toplamlarının?
Sorunun bu sürümden gidebilirsiniz Bildirimi P'gelen Pher elemanın adresinin S / 3 çıkarılarak A, ama şimdi artık hedef değeri gerekmez.
Açıkçası, tüm olası 3 tüpleri test edersek, sorunu O (n 3 ) 'te çözerdik - bu kaba kuvvet temelidir. Daha iyisini yapmak mümkün mü? Tupleleri biraz daha akıllıca seçersek ne olur?
İlk olarak, diziyi sıralamak için biraz zaman harcıyoruz, bu da bize O (n log n) 'nin ilk cezasına mal oluyor. Şimdi bu algoritmayı yürütüyoruz:
for (i in 1..n-2) {
j = i+1 // Start right after i.
k = n // Start at the end of the array.
while (k >= j) {
// We got a match! All done.
if (A[i] + A[j] + A[k] == 0) return (A[i], A[j], A[k])
// We didn't match. Let's try to get a little closer:
// If the sum was too big, decrement k.
// If the sum was too small, increment j.
(A[i] + A[j] + A[k] > 0) ? k-- : j++
}
// When the while-loop finishes, j and k have passed each other and there's
// no more useful combinations that we can try with this i.
}
Bu algoritma, üç işaretçiler, yerleştirir ve i, jve kdizi içinde çeşitli noktalarda. ibaşlangıçta başlar ve yavaş yavaş sonuna kadar gider. kson öğeye işaret eder. jnereden ibaşladığını gösterir. Öğeleri tekrar tekrar kendi endekslerinde toplamaya çalışıyoruz ve her seferinde aşağıdakilerden biri gerçekleşiyor:
- Toplam kesinlikle doğru! Cevabı bulduk.
- Toplam çok küçüktü. Taşı
jsonraki en büyük sayı seçmek daha yakın ucuna.
- Toplam çok büyüktü. Taşı
ksonraki en küçük numarayı seçmek daha yakın başlangıcına.
Her biri için i, bir işaretçi jve kyavaş yavaş daha yakın birbirine alacak. Sonunda birbirlerini geçecekler ve bu noktada bunun için başka bir şey denememiz gerekmiyor i, çünkü aynı unsurları sadece farklı bir düzende toplayacağız. Bu noktadan sonra bir sonrakini dener ive tekrarlarız.
Sonunda, ya yararlı olanakları tüketeceğiz ya da çözümü bulacağız. Dış döngü O (n) kez yürüttüğümüz ve iç döngü O (n) kez yürüttüğümüz için bunun O (n 2 ) olduğunu görebilirsiniz . Gerçekten süslü olursanız, her bir tamsayıyı bir bit vektörü olarak temsil ederek ve hızlı bir Fourier dönüşümü gerçekleştirerek bunu alt karesel olarak yapmak mümkündür, ancak bu, bu cevabın kapsamı dışındadır.
Not: Bu bir röportaj sorusu olduğundan, burada biraz hile yaptım: bu algoritma aynı öğenin birden çok kez seçilmesine izin veriyor. Yani, (-1, -1, 2) (0, 0, 0) gibi geçerli bir çözüm olacaktır. Ayrıca başlıktan da bahsedildiği gibi en yakın cevabı değil, sadece kesin cevapları bulur . Okuyucu için bir alıştırma olarak, onu sadece farklı öğelerle (ancak çok basit bir değişiklik) ve kesin cevapları (aynı zamanda basit bir değişikliktir) nasıl çalıştıracağınızı anlamanıza izin vereceğim.