O (nlogn) Algoritması - İkili dizede eşit aralıklarla üç tane bulun


173

Bu soruyu dün bir Algoritma testinde aldım ve cevabını bulamıyorum. Beni kesinlikle deli ediyor çünkü yaklaşık 40 puan değerindeydi. Sınıfın çoğunun doğru bir şekilde çözmediğini düşünüyorum, çünkü son 24 saat içinde bir çözüm bulamadım.

İsteğe bağlı bir n uzunluğunda uzunluk dizesi verildiğinde, varsa dize içinde eşit aralıklarla yerleştirilmiş üç tane bulun. Bunu O (n * log (n)) zamanında çözen bir algoritma yazın.

Bunun gibi dizeler "eşit aralıklarla yerleştirilmiş" üç diziye sahiptir: 11100000, 0100100100

edit: Bu rastgele bir sayı, bu yüzden herhangi bir sayı için çalışabilmelidir. Verdiğim örnekler "eşit aralıklı" özelliği göstermekti. 1001011 geçerli bir sayı. 1, 4 ve 7 eşit aralıklı olanlardır.


4
Aşağıdakiler mümkün mü: 10011010000? Eşit aralıklarla yerleştirilmiş üç adet 1s (birinci, ikinci, ileri) vardır, ancak ek 1'ler de vardır.
Anna

5
Robert, profesörüne bunun cevabını vermesi ve buraya göndermesi gerekiyor. Bu sorun beni duvardan yukarı çekiyor. Bunu n ^ 2'de nasıl yapacağımı anlayabilirim, ancak n * log (n) değil.
James McMahon

3
Hmm Bunu anlamaya çalışırken çok uzun zaman geçirdim, henüz iyi bir cevapla karşılaşmadım. Belki de soruyu yanlış anladınız? Örneğin, soru soruyorsa, O (n log n) 'de çalışan ve eşit aralıklı bir aralık k aralığı dizisinin konumunu çok daha büyük bir sırayla belirleyen bir algoritma bulun, bu hızlı fourier dönüşümü kullanılarak kolayca yapılabilir.
02'de ldog

2
Prof'iniz bir çözüm veriyorsa, lütfen cevap olarak gönderin.
02'de ldog

5
Klaus Roth'un (diğer şeylerin yanı sıra) her d yoğunluğu> 0 için, her bir en az d * ile {1, ..., N} alt kümelerinin olacağı şekilde doğal bir N sayısı olduğunu kanıtlamak için bir Alan Madalyası 1958 aldığını göz önüne alarak. N elementleri 3 uzunluğunun aritmetik bir ilerlemesini içeriyor, şimdiye kadar hiç kimsenin problem için ikna edici bir algoritma bulamamasına şaşırmadım. Ayrıca bkz. En.wikipedia.org/wiki/Szemer%C3%A9di%27s_theorem
jp

Yanıtlar:


128

En sonunda! Sdcvvc'nin cevabındaki olası ipuçlarını takip ederek , bunu elde ettik: problem için O (n log n) algoritması! Anladıktan sonra da basit. FFT'yi tahmin edenler haklıydı.

Sorun: nS uzunluğunda bir ikili dize verildi ve içinde eşit olarak aralıklı üç tane 1 bulmak istiyoruz. Örneğin, olabilir , burada , n = 9. 2, 5 ve 8. konumlarda eşit olarak 1s aralık bırakmıştır.S110110010

  1. SSoldan sağa tarayın ve L1 konumlarının bir listesini yapın . S=110110010Yukarıdakiler için L = [1, 2, 4, 5, 8] listesine sahibiz. Bu adım O (n) 'dir. Sorun, bulmak için artık uzunluğunda 3 aritmetik ilerlemesi olarak Lbelirgin bulmak için, yani a, b, c olarak Lbu şekilde ba = cb , veya eşdeğer a + c = 2b . Yukarıdaki örnek için, ilerlemeyi bulmak istiyoruz (2, 5, 8).

  2. Bir Make polinomu p şartlarına x k her biri için k içinde L. Yukarıdaki örnek için, polinom p (x) = (x + x 2 + x 4 + x 5 + x 8 ) 'i yapıyoruz . Bu adım O (n) 'dir.

  3. Hızlı Fourier Dönüşümü'nü kullanarak polinom q= p 2'yi bulun . Yukarıdaki örnek için, polinom q (x) = x 16 + 2x 13 + 2x 12 + 3x 10 + 4x 9 + x 8 + 2x 7 + 4x 6 + 2x 5 + x 4 + 2x 3 + x 2 elde ediyoruz . Bu adım O'dur (n log n).

  4. Bazı k inç için x 2k değerine karşılık gelenler dışındaki tüm terimleri yoksay . Yukarıdaki örnek için x 16 , 3x 10 , x 8 , x 4 , x 2 terimlerini alıyoruz . Hiç yapmayı seçerseniz, bu adım O (n) 'dir.L

Burada önemli nokta: Herhangi katsayısı x 2b için b içinde Lolduğu tam çiftlerinin sayısı (a, c) içinde Lbu şekilde a + c = 2b . [CLRS, Örn. 30.1-7] Böyle bir çift daima (b, b) 'dir (yani katsayı en az 1'dir), ancak başka bir çift (a, c) varsa, katsayı en az 3'tür (a, c ) ve (c, a) . Yukarıdaki örnek için, AP (2,5,8) nedeniyle kesin olarak x 10 katsayısı 3'tür. (Bu katsayılar x 2byukarıdaki nedenlerden dolayı her zaman tek sayılar olacaktır. Ve q'daki diğer tüm katsayılar her zaman eşit olacaktır.)

Dolayısıyla algoritma, bu x 2b terimlerinin katsayılarına bakmak ve bunlardan herhangi birinin 1'den büyük olup olmadığına bakmaktır. Hiçbiri yoksa, eşit aralıklı 1'ler yoktur. Orada ise olan bir b içinde Lkatsayısı olan X 2b 1'den daha büyüktür, daha sonra biraz çifti olduğunu biliyoruz (a, c) dışında - (b, b) olan - a + c = 2b . Gerçek çifti bulmak için, sadece her deneyin a içinde L(karşılık gelen C olacaktır 2b-a ) ve bir 1 pozisyonunda olup olmadığını görmek 2b-a içinde S. Bu adım O (n) 'dir.

Hepsi bu kadar millet.


Birisi sorabilir: FFT kullanmamız gerekiyor mu? Beta , flybywire ve rsp gibi birçok cevap, her 1 çifti kontrol eden ve "üçüncü" konumda 1 olup olmadığını gören yaklaşımın sezgiye göre O (n log n) içinde çalışabileceğini önermektedir. çok fazla 1s varsa, kolayca üçlü bulabiliriz ve çok az 1s varsa, tüm çiftleri kontrol etmek biraz zaman alır. Bu sezgi doğru ve basit bir yaklaşım, ne yazık ki, bir O (n daha iyi 2 ), önemli ölçüde daha iyidir. Olduğu gibi sdcvvc cevabı , biz uzunlukta dizeleri "Sette Cantor benzeri" alabilir n = 3 küçlü temsili içinde sadece 0s ve 2s (1s yok) olan konumlarda 1'ler. Böyle bir dize, içinde 2 k = n (log 2) / (log 3) ≈ n 0.63 olana sahiptir ve eşit aralıklı 1s içermez, bu nedenle tüm çiftlerin kontrol edilmesi, içindeki 1'lerin sayısının karesi sırasına göre olur: Ne yazık ki asimptotik olarak (n log n) 'den çok daha büyük olan 4 k ≈ n 1.26 . Aslında, en kötü durum daha da kötü: 1953'te Leo Moser, içinde n 1-c / √ (log n) 1s bulunan ancak eşit aralıklı 1'ler olmayan bu tür dizeleri (etkili bir şekilde) inşa etti , yani bu dizelerde basit yaklaşım Θ (n 2-2c / √ (log n) ) alacaktır- Sadece küçücük daha iyi bit İçeride ISTV melerin RWMAIWi'nin (n 2 ) , şaşırtıcı!


Eşit aralıklı 3 tane içermeyen n uzunluğunda bir dizideki maksimum 1 sayısı (yukarıda gördüğümüz , kolay Cantor benzeri yapıdan en az n 0.63 ve en az n 1-c / √ (log n) ile Moser'ın inşası) - bu OEIS A003002 . Ayrıca doğrudan OEIS A065825'ten k olarak hesaplanabilir , öyle ki A065825 (k) ≤ n <A065825 (k + 1). Bunları bulmak için bir program yazdım ve açgözlü algoritmanın bu kadar uzun bir dize vermediği ortaya çıktı . Örneğin, n = 9 için, 5 1s (110100011) alabiliriz, ancak açgözlü sadece 4 (110110000) verir, n için= 26 11 1s (11001010001000010110001101) alabiliriz, ancak açgözlü sadece 8 verir (1101100001101100000000000000) ve n = 74 için 22 1s (1100001011000100000101101000100000000000000100010110100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Yine de 50'ye kadar (örneğin 38-50'nin tamamı) birkaç yerde aynı fikirde. OEIS referanslarının dediği gibi, Jaroslaw Wroblewski bu soru ile ilgileniyor ve bu ortalama olmayan setler hakkında bir web sitesi sürdürüyor . Kesin sayılar sadece 194'e kadar bilinir.


27
Çok hoş. Etkileyici. Birisinin bunu bir testte bulmasını beklemek biraz fazla gibi görünüyor.
20'de hughdbrown

4
Peki, Adım 1, problemi AP bulmaya çevirmek basittir. Adım 3, polinomların O (n log n) zamanında çoğaltılabileceği sadece bir gerçektir. Asıl hile ve problemi zorlaştıran şey, 11011'i katsayıları olan [1,1,0,1,1], vb. Gibi polinom olarak düşünme fikri. Bu, akıllıca ve genellikle kullanışlı bir fikir. Euler'e dönüş yolu. [Modern bir sergi için Wilf'in müthiş "generatingfunctionology" kitabına bakınız: math.upenn.edu/~wilf/DownldGF.html ] Bu, öğrencilerin son bellekte işlev üretmeye maruz kalıp kalmadıklarına bağlıdır. :-)
ShreevatsaR

2
Üzgünüm, hesaplamam tamamen yanlış. 110110010 ^ 2 = 12124214302200100 olmalıdır. Ama fikir geçerli. Sadece 3. pozisyona dikkat edin.
Guillermo Phillips

11
Çok etkileyici. Bu konuyu / soruyu bir araya getirmek ve bir çözüm bulmak gerçekten harika. Bunun mümkün olmadığını düşünmeye başlamıştım. Ayrıca, bu profesör kötüdür.
KingNestor

1
@RexE: p derece n-1 ise (n terimi varsa), q = p ^ 2 derecesi 2n-2'dir (en fazla 2n-1 terimi vardır). N ^ 2'yi nasıl aldın? (Ayrıca, FFT kullanarak O (n log n) zamanında n derece iki polinomunun çoğaltılması oldukça standart bir işlemdir; lütfen cevaptaki bağlantıya tıklayın veya Wikipedia makalesine bakın .)
ShreevatsaR

35

Bu makalede (1999) sorununuza ORTALAMA denir :

Problemden bir ikinci dereceden bir azalma varsa bir sorun 3SUM zordur. 3SUM: n tamsayı kümesi A verildiğinde, A'da b + c = 0 olacak şekilde a, b, c öğeleri var mı? AVERAGE öğesinin 3SUM zor olup olmadığı bilinmemektedir. Bununla birlikte, tanımını atladığımız ORTALAMA'dan 3SUM'a basit bir doğrusal zaman azalması var.

Wikipedia :

Tamsayılar [...u ... u] aralığında olduğunda, 3SUM, S'yi bir bit vektörü olarak temsil ederek ve FFT kullanarak bir evrişim gerçekleştirerek O (n + u lg u) zamanında çözülebilir.

Bu sorunu çözmek için yeterlidir :).

Ne çok önemlidir (log n, n) sıfır ve kendisi sayısı açısından karmaşık olduğu O, olanlar değil sayısı (olduğu gibi, bir dizi olarak verilebilir [1,5,9,15]). Bir dizi bir aritmetik ilerlemesi, 1 'sayısı koşulları olup olmadığını kontrol edilmesi zordur ve bir hızlı algoritma O (n den 1999 tarihi itibariyle bu kağıt göre 2 bu varolmayan) bilinen ve tahmin ediliyor. Bunu dikkate almayan herkes açık bir sorunu çözmeye çalışıyor.

Diğer ilginç bilgiler, çoğunlukla irrevelant:

Alt sınır:

Kolay bir alt sınır Cantor benzeri kümedir (üçlü genişlemelerinde 1 içermeyen 1..3 ^ n-1 sayıları) - yoğunluğu n ^ (log_3 2) (yaklaşık 0.631). Bu nedenle, kümenin çok büyük olup olmadığını kontrol etmek ve ardından tüm çiftleri kontrol etmek O (n log n) almak için yeterli değildir. Diziyi daha akıllıca araştırmalısınız. Daha iyi bir alıntılanmıştır bağlı düşük değerler burada - bu n var 1-c / (log (n)) ^ (1/2) . Bu, Cantor setinin optimal olmadığı anlamına gelir .

Üst sınır - eski algoritmam:

Büyük n için, aritmetik ilerleme içermeyen bir {1,2, ..., n} alt kümesinin en fazla n / (log n) ^ (1/20) elemanı olduğu bilinmektedir. Aritmetik progresyondaki üçlülerde kağıt daha fazlasını kanıtlar: küme n * 2 28 * (log log n / log n) 1/2 elementten fazlasını içeremez . Böylece bu bağlantının sağlanıp sağlanmadığını kontrol edebilir ve eğer değilse çiftleri saf şekilde kontrol edebilirsiniz. Bu O (n 2 * log log n / log n) algoritmasıdır, O (n 2 ) ' den daha hızlıdır . Ne yazık ki "Üçlü ..." Springer'da - ancak ilk sayfa mevcut ve Ben Green'in sergisine buradan ulaşabilirsiniz , sayfa 28, teorem 24.

Bu arada, gazeteler 1999'dan - bahsettiğim ilk yılla aynı yıl, bu yüzden muhtemelen ilk sonuçtan bahsetmiyor.


2
Harika cevap, ilk sorun bu konuda kesin bir şey söylüyor. Böylece Cantor benzeri küme n ^ 0.63 1s değerine sahiptir, bu da "tüm 1s çiftlerini kontrol et" algoritmasının en kötü durumda en az n ^ 1.26 (≫ n log n) olduğu anlamına gelir . Szemeredi'nin gazetesinde alıntılanan alt sınır (alıntıladığı BTW Moser kağıdı burada mevcuttur: books.google.com/books?id=Cvtwu5vVZF4C&pg=PA245 ) aslında n ^ (2-o (1)) anlamına geliyor gibi görünüyor, ancak biraz dikkatli olun çünkü orada {1, ..., n} 'dan çizilen rakamlarımız var, ama işte n dizisindeki sayıların toplamı .
ShreevatsaR

Er, içinde n ^ (log_3 2) 1s içeren ve eşit olarak aralıklı üç tane olmayan "Cantor benzeri" ikili dizi tam olarak nedir?
ShreevatsaR

Örnek: 101000101000000000101000101. Uzunluğu 3 ^ n'dir ve 2 ^ n'dir (yani n ^ 0.63 yoğunluk). 1'lerin yerlerini ikili olarak yazarsanız, {0,2,20,22,200,202,220,222} olacaktır. Bunu düşünmenin bir başka olası yolu, bir dizi almak ve normal Cantor seti yapısında olduğu gibi "orta" olanları sürekli olarak kaldırmaktır: 111111111 -> 111000111 -> 101000101. Aritmetik ilerleme içermemesinin nedeni: eğer x , y, z bir tane oluşturdu, sonra y = (x + z) / 2 ve x ve z bazı genleşme yerlerinde farklılık gösterir. En önemlisini al. Diyelim ki x 0 ve z 2'dir. Sonra y'nin 1 olması gerekir. çelişki.
sdcvvc

3
Yine harika bir araştırma! 2008 3SUM belgesini takip ettim ve CLRS Egzersizine atıfta bulundum. 30.1-7, hangi cevabı aldığımı gördükten sonra - O (n log n) algoritması aslında oldukça basit! (Sadece bir polinom / üretme fonksiyonunun karesi.) Aşağıdaki cevabı gönderdim. (Şimdi daha önce düşünmediğim için kendimi tekmeliyorum ... basit çözümler her zaman bu reaksiyonu ortaya çıkarır: p)
ShreevatsaR

Bu yüzden sınav sorusunun cevabı "Bu problem 3-SUM zor problemine indirgenebilir ve 3-SUM hard'ın alt-karesel çözümü yoktur, bu yüzden O (n logn) 'da bu problem çözülemez. " Evet?
09:57

8

Bu bir çözüm değil, Olexiy'in ne düşündüğüne benzer bir düşünce hattı

Maksimum sayıda olan diziler oluşturmakla oynuyordum ve hepsi oldukça ilginç, 125 basamağa sahibim ve işte mümkün olduğunca çok sayıda '1' bit eklemeye çalışarak bulduğu ilk 3 sayı:

  • 11011000011011000000000000001101100001101100000000000000000000000000000000000000000110110000110110000000000000011011000011011
  • 10110100010110100000000000010110100010110100000000000000000000000000000000000000000101101000101101000000000000101101000101101
  • 10011001010011001000000000010011001010011001000000000000000000000000000000000000010011001010011001000000000010011001010011001

Hepsinin fraktal olduğuna dikkat edin (kısıtlamalar göz önüne alındığında çok şaşırtıcı değil). Geriye doğru düşünmede bir şey olabilir, belki de ip karakteristik bir fraktal değilse , tekrar eden bir desene sahip olmalıdır?

Bu sayıları tanımlamak için daha iyi terim için beta'ya teşekkürler.

Güncelleme: Ne yazık ki, desen gibi yeterince büyük bir ilk dize ile başlarken bozuluyor gibi görünüyor: 10000000000001:

100000000000011
10000000000001101
100000000000011011
10000000000001101100001
100000000000011011000011
10000000000001101100001101
100000000000011011000011010000000001
100000000000011011000011010000000001001
1000000000000110110000110100000000010011
1000000000000110110000110100000000010011001
10000000000001101100001101000000000100110010000000001
10000000000001101100001101000000000100110010000000001000001
1000000000000110110000110100000000010011001000000000100000100000000000001
10000000000001101100001101000000000100110010000000001000001000000000000011
1000000000000110110000110100000000010011001000000000100000100000000000001101
100000000000011011000011010000000001001100100000000010000010000000000000110100001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011001000000000000000000000010010000010000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001001000000000000000000000000000000000000110010000000000000000000000100100000100000011
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001000001000000110000000000001

2
Kutsal * @ !!, bunlar KIRILGAN! Bu tutarsa, 1'lerin sayısına bir üst sınır koyar ve O (n) 'den daha azdır.
Beta

fraktallar, bu onları tanımlamak için çok daha iyi bir terim. Teşekkürler
z -

İlginçtir, bu desenler Cantor'un üçlü setine çok benzemektedir ( en.wikipedia.org/wiki/Cantor_set ). Eğer öyleyse, o zaman
oların

Üçlü olmayan maksimum 1 sayısı olan dizilerin, algoritmanın en kötü çalışma süresi ile doğrudan ilişkili olduğu açık mı? 1'lerin çok sayıda dizeye sahip olabileceğiniz düşünülebilir, ancak bu üçlüler algoritmanız tarafından geç incelenen pozisyonlarda olduğu için sadece üçleri çok geç bulursunuz.
ShreevatsaR

3
Dizelerdeki toplam sayısı ile karşılaştırıldığında analizlerim, dizi sayısı ile dize boyutu arasında doğrusal bir ilişki olduğunu gösteriyor, bu da bize şunu söyleyen mutlu bir üst sınır olmadığına inanmamı sağlıyor. bir dizedeki sayısı belirli bir dize için en fazla log (n) olur. Böylece tüm dizginin kendisi ile değil, sadece konumlarıyla ilgilenen çözümler de O (n ^ 2) olacaktır. Veya, daha doğrusu, O (n + m ^ 2), burada m, dizgedekilerin sayısıdır ve n, dizenin boyutudur ve m, büyük teta (n) 'dir.
00'da Welbog

6

O (n ^ 2) gibi görünen basit bir yaklaşımın aslında O (n ln (n)) gibi daha iyi bir şey vereceğinden şüpheleniyorum. Test edilmesi en uzun süren diziler (herhangi bir n için) üçlü içermeyen dizilerdir ve dizide olabilen 1'lerin sayısına ciddi kısıtlamalar getirir.

Bazı el sallayan argümanlar buldum, ama düzenli bir kanıt bulamadım. Karanlıkta bir bıçak alacağım: Cevap, profesörün çok uzun zamandır bildiği çok açık bir fikir olduğu açıktır, ancak öğrenciler için çok zor. (Ya o ya da onu kapsayan ders boyunca uyudun.)


2
lol, hayır derslerde uyumadım. Birkaç başka öğrenciyle konuştum ve kimsenin onu nasıl çözeceği konusunda net bir fikri yoktu. Çoğu kısmi kredi almak için bölmek ve fethetmek hakkında bazı BS yazdı.
Robert Parker

3

Revizyon: 2009-10-17 23:00

Ben çok sayıda (20 milyon dizeleri gibi) üzerinde çalıştım ve şimdi bu algoritmanın O (n logn) olmadığına inanıyorum. Buna rağmen, yeterince havalı bir uygulama ve gerçekten hızlı çalışmasını sağlayan bir dizi optimizasyon içeriyor. 25 saniyenin altında 24 veya daha az basamaklı ikili dizgilerin tüm düzenlemelerini değerlendirir.

Kod, 0 <= L < M < U <= X-1bugün erken gözlem dahil olmak üzere güncelledim .


orijinal

Bu, kavram olarak, cevapladığım başka bir soruya benzer . Bu kod aynı zamanda bir seride üç değere baktı ve bir üçlünün bir koşulu yerine getirip getirmediğini belirledi. İşte bundan uyarlanmış C # kodu:

using System;
using System.Collections.Generic;

namespace StackOverflow1560523
{
    class Program
    {
        public struct Pair<T>
        {
            public T Low, High;
        }
        static bool FindCandidate(int candidate, 
            List<int> arr, 
            List<int> pool, 
            Pair<int> pair, 
            ref int iterations)
        {
            int lower = pair.Low, upper = pair.High;
            while ((lower >= 0) && (upper < pool.Count))
            {
                int lowRange = candidate - arr[pool[lower]];
                int highRange = arr[pool[upper]] - candidate;
                iterations++;
                if (lowRange < highRange)
                    lower -= 1;
                else if (lowRange > highRange)
                    upper += 1;
                else
                    return true;
            }
            return false;
        }
        static List<int> BuildOnesArray(string s)
        {
            List<int> arr = new List<int>();
            for (int i = 0; i < s.Length; i++)
                if (s[i] == '1')
                    arr.Add(i);
            return arr;
        }
        static void BuildIndexes(List<int> arr, 
            ref List<int> even, ref List<int> odd, 
            ref List<Pair<int>> evenIndex, ref List<Pair<int>> oddIndex)
        {
            for (int i = 0; i < arr.Count; i++)
            {
                bool isEven = (arr[i] & 1) == 0;
                if (isEven)
                {
                    evenIndex.Add(new Pair<int> {Low=even.Count-1, High=even.Count+1});
                    oddIndex.Add(new Pair<int> {Low=odd.Count-1, High=odd.Count});
                    even.Add(i);
                }
                else
                {
                    oddIndex.Add(new Pair<int> {Low=odd.Count-1, High=odd.Count+1});
                    evenIndex.Add(new Pair<int> {Low=even.Count-1, High=even.Count});
                    odd.Add(i);
                }
            }
        }

        static int FindSpacedOnes(string s)
        {
            // List of indexes of 1s in the string
            List<int> arr = BuildOnesArray(s);
            //if (s.Length < 3)
            //    return 0;

            //  List of indexes to odd indexes in arr
            List<int> odd = new List<int>(), even = new List<int>();

            //  evenIndex has indexes into arr to bracket even numbers
            //  oddIndex has indexes into arr to bracket odd numbers
            List<Pair<int>> evenIndex = new List<Pair<int>>(), 
                oddIndex = new List<Pair<int>>(); 
            BuildIndexes(arr, 
                ref even, ref odd, 
                ref evenIndex, ref oddIndex);

            int iterations = 0;
            for (int i = 1; i < arr.Count-1; i++)
            {
                int target = arr[i];
                bool found = FindCandidate(target, arr, odd, oddIndex[i], ref iterations) || 
                    FindCandidate(target, arr, even, evenIndex[i], ref iterations);
                if (found)
                    return iterations;
            }
            return iterations;
        }
        static IEnumerable<string> PowerSet(int n)
        {
            for (long i = (1L << (n-1)); i < (1L << n); i++)
            {
                yield return Convert.ToString(i, 2).PadLeft(n, '0');
            }
        }
        static void Main(string[] args)
        {
            for (int i = 5; i < 64; i++)
            {
                int c = 0;
                string hardest_string = "";
                foreach (string s in PowerSet(i))
                {
                    int cost = find_spaced_ones(s);
                    if (cost > c)
                    {
                        hardest_string = s;
                        c = cost;
                        Console.Write("{0} {1} {2}\r", i, c, hardest_string);
                    }
                }
                Console.WriteLine("{0} {1} {2}", i, c, hardest_string);
            }
        }
    }
}

Temel farklar:

  1. Kapsamlı çözüm arama
    Bu kod, bu algoritma için çözülmesi gereken en zor girdiyi bulmak için bir güç kümesi oluşturur.
  2. Çözülmesi en zor olana karşı tüm çözümler
    Önceki sorunun kodu bir python jeneratörü kullanarak tüm çözümleri üretti. Bu kod, her desen uzunluğu için en zor olanı görüntüler.
  3. Puanlama algoritması
    Bu kod, orta elemandan sol ve sağ kenarına olan mesafeyi kontrol eder. Python kodu toplamın 0'ın altında mı altında mı olduğunu test etti.
  4. Bir adayda yakınsama
    Geçerli kod , bir aday bulmak için ortadan ortaya doğru çalışır. Önceki problemdeki kod kenarlardan ortaya doğru çalıştı. Bu son değişiklik büyük bir performans artışı sağlıyor.
  5. Çift ve tek havuzların kullanımı
    Bu yazının sonundaki gözlemlere dayanarak, kod, M'yi sabit tutarak L ve U'yu bulmak için çift sayı çiftlerini arar. Bu, bilgileri önceden hesaplayarak arama sayısını azaltır. Buna göre, kod FindCandidate ana döngüsünde iki dolaylı düzey kullanır ve her bir orta öğe için iki FindCandidate çağrısı gerektirir: bir kez çift sayılar için ve bir kez tek olanlar için.

Genel fikir, verilerin ham temsili değil dizinler üzerinde çalışmaktır. 1'lerin göründüğü bir dizinin hesaplanması, algoritmanın, verilerin uzunluğu ile orantılı olarak değil, verilerdeki 1'lerin sayısıyla orantılı olarak çalışmasına izin verir. Bu standart bir dönüşümdür: sorunu eşdeğer tutarken daha hızlı çalışmayı sağlayan bir veri yapısı oluşturun.

Sonuçlar güncel değil: kaldırıldı.


Düzenleme: 2009-10-16 18:48

Hesaplanması zor verilerin temsilcisi olarak diğer yanıtlarda bir miktar güvence verilen yx'in verilerinde bu sonuçları alıyorum ... Bunları kaldırdım. Güncel değiller.

Bu veri benim algoritma için zor değil, bu yüzden yx fraktallar çözmek için en zor olduğu varsayım yanlış olduğunu düşünüyorum. Belirli bir algoritma için en kötü durum, algoritmanın kendisine bağlı olacaktır ve muhtemelen farklı algoritmalar arasında tutarlı olmayacaktır.


Düzenleme: 2009-10-17 13:30

Bununla ilgili daha fazla gözlem.

İlk olarak, 0'ların ve 1'lerin dizesini 1'lerin her konumu için bir dizin dizisine dönüştürün. Diyelim ki A dizisinin uzunluğu X.

0 <= L < M < U <= X-1

öyle ki

A[M] - A[L] = A[U] - A[M]

veya

2*A[M] = A[L] + A[U]

A [L] ve A [U] çift sayıyı topladığından, (çift, tek) veya (tek, çift) olamazlar. Bir eşleşme arayışı, A [] 'yı tek ve çift havuzlara bölerek ve tek ve hatta adayların havuzlarında A [M]' de eşleşmeler arayarak geliştirilebilir.

Ancak, bu bir algoritma geliştirmesinden ziyade bir performans optimizasyonudur. Karşılaştırma sayısı düşmeli, ancak algoritmanın sırası aynı olmalıdır.


Düzenle 2009-10-18 00:45

Yine de, adayları eşit ve garip bir şekilde ayırmakla aynı şekilde başka bir optimizasyon gerçekleşiyor. Üç dizin 3'ün katlarına (a, a + x, a + 2x - mod 3, a ve x ne olursa olsun 0) katılması gerektiğinden, L, M ve U'yu mod 3 değerlerine ayırabilirsiniz :

M  L  U
0  0  0
   1  2
   2  1
1  0  2
   1  1
   2  0
2  0  1
   1  0
   2  2

Aslında, bunu çift / tek gözlemle birleştirebilir ve mod 6 değerlerine ayırabilirsiniz:

M  L  U
0  0  0
   1  5
   2  4
   3  3
   4  2
   5  1

ve bunun gibi. Bu, daha fazla performans optimizasyonu sağlar, ancak algoritmik bir hızlanma sağlamaz.


2

Henüz bir çözüm bulamadık :(, ama bazı fikirleri var.

Ya bir ters problemden başlarsak: maksimum 1s ve eşit aralıklı üçlüsü OLMADAN bir dizi oluşturun. Maksimum 1s sayısının o (n) olduğunu kanıtlayabilirseniz, tahmininizi yalnızca 1'ler listesinden yineleyerek artırabilirsiniz.


1'lerin sayısı kesinlikle O (n) ile sınırlıdır. O (n ** 2) olamaz, doğru - 1'lerin sayısı veriden daha hızlı büyüyor mu? Önemli soru, üst sınırın bundan daha düşük olup olmadığıdır.
hughdbrown

Ben küçük o kullandım, büyük değil
Olexiy

2

Bu yardımcı olabilir ....

Bu sorun aşağıdakilere azalır:

Bir pozitif tamsayı dizisi verildiğinde, bir önek ve bir sonek olarak bölünmüş bitişik bir alt diziyi bulun, böylece alt dizinin önekinin toplamı, alt dizinin sonekinin toplamına eşit olur.

Örneğin, bir dizi verilen [ 3, 5, 1, 3, 6, 5, 2, 2, 3, 5, 6, 4 ], biz, içinde bir sonuç bulmak [ 3, 6, 5, 2, 2]bir önek ile [ 3, 6 ]önek toplamı ile 9ve bir sonek [ 5, 2, 2 ]sonek toplamı 9.

Azaltma aşağıdaki gibidir:

Sıfırlar ve birler dizisi verildiğinde ve en soldan başlayarak sağa doğru ilerlemeye devam edin. Başka bir karşılaşma ile karşılaştığınız her seferinde, bir öncekiyle karşılaşıldığından bu yana yapılan hamle sayısını kaydedin ve bu sayıyı elde edilen sıraya ekleyin.

Örneğin, bir dizi verildiğinde [ 0, 1, 1, 0, 0, 1, 0, 0, 0, 1 0 ], azalmasını bulurduk [ 1, 3, 4]. Bu azalma, biz mücavir altdizisi hesaplamak [ 1, 3, 4], önek [ 1, 3]toplamı 4, ve eki [ 4 ]toplamı 4.

Bu azalma hesaplanabilir O(n).

Ne yazık ki, buradan nereye gideceğimi bilmiyorum.


1
Daha kompakt bir gösterimdir, ancak zaman karmaşıklığına yardımcı olmaz. "Önek" bölüm kümesi, "1" in tüm oluşumlarında O (n ^ 2) olan tüm çiftler için izomorfiktir.
p00ya

Görünüşe göre bitişik alt toplamlarla ilgilenen algoritmalar var. Ne yazık ki, hepsi O (n) 'de maksimum toplam ile bitişik alt diziyi bulmakla uğraşmaktadır.
yfeldblum

@ p00ya bu doğru değil. Bu algoritmayı kullanarak zaman kopleksitesi, Cantor tarafından oluşturulan dizgideki assupton ((3/2) ^ (log (n) / log (3))) olan ve alan karmaşıklığı bu hale gelen yanlış olanların sayısının üst sınırına bağlıdır. ancak zaman karmaşıklığı n ile çarpılır. İkinci cevabımı kontrol et. (olumsuz değil): D
Luka Rahne

@ralu: Cantor tarafından oluşturulan dizelerin en kötü durum olduğu varsayımı altındadır, bu yanlıştır. Kayıt için, çiftlerin sayısı kesinlikle O (n ^ 2); ama sanırım bu sonuçlar göz önüne alındığında büyük Omega (n ^ 2) olduğunu ima ediyordum, bu da büyük Omega çiftlerinde (n ^ (2 / 1.52) )) ispat yoluyla veya büyük Omega (n ^ (4/3))
p00ya

1

Basit problem türü için (yani sadece aralarında üç "1" ile (yani sıfır veya daha fazla) "0 " ile arama yaparsınız ), Oldukça basit: Diziyi her "1" de bölebilir ve iki bitişik diziyi arayabilirsiniz. aynı uzunluk (elbette ikinci sıra sonuncusu değildir). Açıkçası, bu O (n) zamanda yapılabilir.

Daha karmaşık sürüm için (yani bir indeks i ve bir g > 0 boşluğu ararsınızs[i]==s[i+g]==s[i+2*g]=="1" ), eminim, O (n log n) çözümü varsa, muhtemelen O (n²) üçüzleri Bu özellik (hepsini bir dizi düşünün, yaklaşık n² / 2 gibi üçüz vardır). Tabii ki, bunlardan sadece birini arıyorsunuz, ama şu anda hiçbir fikrim yok, nasıl bulacağım ...


Evet, sorunun daha zor versiyonunu tartışıyoruz. Yine de, n * log (n) çözümü mümkün olabilir.
Olexiy

1
Aslında n O (n ^ 3) olası üçlü olan 3 seçim var, sanırım yaklaşık n ^
2/2 dediğinde

@gmatt: n 2'yi seçmek yeterlidir; iki tane 1'i düzeltirsek, üçüncülüğün konumu belirlenir ve bu konumda bir 1 olup olmadığını görmek için sabit zaman.
ShreevatsaR

@ShreevatsaR: evet doğru bence, kısıtsız durumu düşünüyordum.
21'de ldog

1
@gmatt: aslında, yukarıda tanımlandığı gibi 0 <= i <(n-3) ve 0 <g <(ni-1) / 2 kısıtlamaları olan Tuples'ı (i, g) arıyoruz, bu nedenle n ^
2/2

1

Eğlenceli bir soru, ancak iki '1' arasındaki gerçek desenin önemli olmadığını anladıktan sonra, algoritma şu hale gelir:

  • tarama '1' arayın
  • bir sonraki konumdan başlayarak başka bir '1' taraması yapın (dizinin sonuna ek olarak geçerli ilk '1'den uzaklığa veya 3.' 1 'sınırların dışında olur)
  • 2. '1' pozisyonunda artı ilk 1 'mesafesine üçüncü bir' 1 'bulunursa eşit boşluklara sahip oluruz.

Kod, JTest moda, (Bu kodun en verimli olduğu için yazılmadığını ve ne olduğunu görmek için bazı println'ler eklediğimi unutmayın.)

import java.util.Random;

import junit.framework.TestCase;

public class AlgorithmTest extends TestCase {

 /**
  * Constructor for GetNumberTest.
  *
  * @param name The test's name.
  */
 public AlgorithmTest(String name) {
  super(name);
 }

 /**
  * @see TestCase#setUp()
  */
 protected void setUp() throws Exception {
  super.setUp();
 }

 /**
  * @see TestCase#tearDown()
  */
 protected void tearDown() throws Exception {
  super.tearDown();
 }

 /**
  * Tests the algorithm.
  */
 public void testEvenlySpacedOnes() {

  assertFalse(isEvenlySpaced(1));
  assertFalse(isEvenlySpaced(0x058003));
  assertTrue(isEvenlySpaced(0x07001));
  assertTrue(isEvenlySpaced(0x01007));
  assertTrue(isEvenlySpaced(0x101010));

  // some fun tests
  Random random = new Random();

  isEvenlySpaced(random.nextLong());
  isEvenlySpaced(random.nextLong());
  isEvenlySpaced(random.nextLong());
 }

 /**
  * @param testBits
  */
 private boolean isEvenlySpaced(long testBits) {
  String testString = Long.toBinaryString(testBits);
  char[] ones = testString.toCharArray();
  final char ONE = '1';

  for (int n = 0; n < ones.length - 1; n++) {

   if (ONE == ones[n]) {
    for (int m = n + 1; m < ones.length - m + n; m++) {

     if (ONE == ones[m] && ONE == ones[m + m - n]) {
      System.out.println(" IS evenly spaced: " + testBits + '=' + testString);
      System.out.println("               at: " + n + ", " + m + ", " + (m + m - n));
      return true;
     }
    }
   }
  }

  System.out.println("NOT evenly spaced: " + testBits + '=' + testString);
  return false;
 }
}

4
Yanılmıyorsam, dış döngü n kez çalıştığı ve iç döngü ortalama olarak n / 2 kez çalıştığı için bu O (n²) 'dir.
StriplingWarrior

Dış döngü n kez çalışır ve iç döngü ortalama olarak n / 4 çalışır, ancak sadece bir '1' i takip eden konumlardan başlatılır. Bir n ^ 2 davranışına yaklaşmak için '1' sayısının yüksek olması gerekir, bu da erken doğru sonuçla sonuçlanır ve böylece işleme durur. Bu nedenle n ^ 2 davranışı hiçbir zaman gerçekleşmez. Verilerin bilinen özelliklerine göre bir O belirleme şu anda beni kaçıyor.
rsp

Ne yazık ki, ortalama gerçek yaşam zamanı değil, teorik Big O zamanı. Ve yaklaşımınız O (n²) (benimkiyle aynı çünkü yaklaşımınız benimkiyle aynı)
DaClown

Ortalama davranıştan değil, maksimum davranıştan bahsediyordum. Testi geçemeyen maksimum entropinin dizede log n '1'ler içerdiğinin kanıtlanması sürpriz olmaz.
rsp

Dış döngüdeki dizini, iç döngüde bulunan ilk 1 dizinine göre güncellerseniz, yani (olanlar [m] == ONE) {n = m}? Bu büyük O'ya yardımcı olur mu?
steamer25

1

İşe yarayacak bir böl ve fethet yaklaşımı düşündüm.

İlk olarak, ön işlemede, giriş boyutunuzun yarısından ( n / 3) küçük tüm sayıları bir listeye eklemeniz gerekir .

Bir dize verildiğinde: 0000010101000100(bu özel örneğin geçerli olduğunu unutmayın)

Tüm astarları (ve 1) 1'den (16/2) bir listeye ekleyin: {1, 2, 3, 4, 5, 6, 7}

Sonra ikiye bölün:

100000101 01000100

Boyut 1 dizelerine ulaşıncaya kadar bunu yapmaya devam edin. İçinde 1 olan tüm boyut bir dizeler için dizenin dizinini olasılıklar listesine ekleyin; aksi takdirde, hata için -1 döndürür.

Ayrıca, her bir başlangıç ​​diziniyle ilişkili, hala mümkün olan boşluk mesafelerinin bir listesini döndürmeniz gerekir. (Yukarıda yaptığınız listeyle başlayın ve hareket halindeyken sayıları kaldırın) Burada boş bir liste yalnızca bir 1 ile uğraştığınız anlamına gelir ve bu nedenle bu noktada herhangi bir boşluk mümkün olabilir; aksi takdirde liste, dışlanması gereken boşluklar içerir.

Yukarıdaki örnekle devam edelim:

1000 0101 0100 0100

10 00 01 01 01 00 01 00

1 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0

İlk birleştirme adımında, şimdi ikiden oluşan sekiz setimiz var. İlkinde, bir küme olasılığımız var, ancak diğer sıfırın orada olması nedeniyle 1 ile boşluk bırakmanın imkansız olduğunu öğreniyoruz. Bu nedenle 1 (aralık için) imkansız olduğu için 0 (dizin için) ve {2,3,4,5,7} değerlerini döndürüyoruz. İkincisinde, hiçbir şeyimiz yok ve -1'e geri dönüyoruz. Üçüncüsü, indeks 5'te boşluk bırakılmamış bir eşleşmemiz var, bu yüzden 5 dönüşü, {1,2,3,4,5,7}. Dördüncü çiftte 7, {1,2,3,4,5,7} döndürüyoruz. Beşinci bölümde, 9 dönüşü, {1,2,3,4,5,7}. Altıncı sırada -1 döndürün. Yedinci sırada 13 dönüş, {1,2,3,4,5,7}. Sekizinci'de -1 döndür.

Tekrar dörtlü dört set halinde birleştirdik:

1000: Dönüş (0, {4,5,6,7}) 0101: Dönüş (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6 , 7}) 0100: Geri Dönüş (9, {3,4,5,6,7}) 0100: Geri Dönüş (13, {3,4,5,6,7})

Sekiz set halinde birleştirmek:

10000101: Dönüş (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7}) 01000100: Dönüş (9, {4,7}), (13, {3,4,5,6,7})

On altılık bir kümeye birleştiğinde:

10000101 01000100

İlerledikçe, şimdiye kadar tüm olasılıkları kontrol etmeye devam ediyoruz. Bu adıma kadar dizenin sonunu aşan şeyleri bıraktık, ancak şimdi tüm olasılıkları kontrol edebiliriz.

Temel olarak, ilk 1'i 5 ve 7 aralıklarla kontrol ediyor ve 1'lere kadar sıralanmadığını buluyoruz. (Her bir kontrolün lineer zaman değil SABİT olduğunu unutmayın) Sonra ikincisini (indeks 5) 2, 3, 4, 5, 6 ve 7 aralıklarıyla kontrol ederiz, yoksa yaparız, ancak 2'de durabiliriz aslında eşleşir.

Uf! Bu oldukça uzun bir algoritma.

Son adımdan dolayı O (n log n) olup olmadığını% 100 bilmiyorum , ancak oraya kadar her şey kesinlikle söyleyebildiğim kadarıyla O (n log n) . Buna daha sonra geri döneceğim ve son adımı düzeltmeye çalışacağım.

EDIT: Cevabımı Welbog'un yorumunu yansıtacak şekilde değiştirdi. Hata için özür dileriz. Daha sonra tekrar yazdığımı deşifre etmek için biraz daha zaman bulduğumda da sahte kod yazacağım. ;-)


Algoritmanızı takip etmiyorum, ama aslında O (n log n) olmaya çalışan bir algoritmayı denediğiniz için +1
ldog

Teşekkürler. Daha fazla zaman bulduğumda daha iyi açıklamaya çalışacağım (belki bazı sahte kodlar yazabilirim).
Platinum Azure

Neden sadece asal boşluk aralığına bakıyorsunuz? Nasıl bir dizeyle eşleşmeyi önerirsin 100010001? Yaklaşımınızı doğru bir şekilde anlarsam, eşleşemez, çünkü doğru cevabı (0,{4})hesaplamak mümkün değildir. Listenizde primer olmayanlara ihtiyacınız olduğu göz önüne alındığında, O (n log (n)) 'den daha yüksek bir şekilde kontrol etmeniz gereken olasılık listelerini şişiren patolojik dizeler bulmak kolaydır.
Welbog

Yemin ederim, başlangıçta katlar yapıyordum, ama cevabımı yarıda değiştirdim ve her şeyi değiştiremedim. Afedersiniz. Kısaca düzelecek
Platinum Azure

3
Bunun O (n log n) olduğunu sanmıyorum. İlk birleştirme adımında, her biri muhtemelen bir O (n) olası aralık kümesi döndüren (n / 2) kümelerini tedavi edersiniz. Ne yazık ki bu sadece O (n ^ 2) yapar.
MartinStettner

1

Burada kaba tahminde bulunacağım ve karmaşıklığımın hesaplanmasında daha iyi olanların algoritmamın O gösteriminde nasıl yürüdüğü konusunda bana yardımcı olacağım

  1. verilen ikili dize 0000010101000100 (örnek olarak)
  2. kırpma kafası ve sıfır kuyruğu -> 00000 101010001 00
  3. önceki hesaplamadan 101010001 elde ediyoruz
  4. orta bitin 'bir' olup olmadığını kontrol edin, doğruysa, eşit olarak eşit aralıklı üç tane 'bulundu' (yalnızca bit sayısı tek sayılıysa)
  5. korelasyonel olarak, kalan kırpılmış bit sayısı çift sayılıysa, baş ve kuyruk 'bir' eşit aralıklı 'bir'in parçası olamaz,
  6. 1010100001'i örnek olarak kullanıyoruz (çift numaralı ürün olmak için ekstra bir 'sıfır' ile), bu durumda tekrar kırpmamız gerekiyor, sonra -> 10101 00001 olur
  7. önceki hesaplamadan 10101 alıyoruz ve orta biti kontrol ediyoruz ve eşit aralıklı biti tekrar bulduk

Bunun için karmaşıklığı nasıl hesaplayacağımı bilmiyorum, kimse yardımcı olabilir mi?

edit: fikrimi göstermek için bazı kod ekleyin

edit2: kodumu derlemeye çalıştı ve bazı büyük hatalar buldu, düzeltildi

char *binaryStr = "0000010101000100";

int main() {
   int head, tail, pos;
   head = 0;
   tail = strlen(binaryStr)-1;
   if( (pos = find3even(head, tail)) >=0 )
      printf("found it at position %d\n", pos);
   return 0;
}

int find3even(int head, int tail) {
   int pos = 0;
   if(head >= tail) return -1;
   while(binaryStr[head] == '0') 
      if(head<tail) head++;
   while(binaryStr[tail] == '0') 
      if(head<tail) tail--;
   if(head >= tail) return -1;
   if( (tail-head)%2 == 0 && //true if odd numbered
       (binaryStr[head + (tail-head)/2] == '1') ) { 
         return head;
   }else {
      if( (pos = find3even(head, tail-1)) >=0 )
         return pos;
      if( (pos = find3even(head+1, tail)) >=0 )
         return pos;
   }
   return -1;
}

@ recursive Ben daha sonra kafasına 111 = olmak için kırpmak find3even (kafa + 1, kuyruk) çağrı ulaştığında çalışacağını düşünüyorum, benim için tekrar kontrol edebilir misiniz?
andycjw

@recursive sözde çok sıkı ve özlü değil daha önce yapılmış kodu, açıklamak daha iyi eklenen kod I kontrol ediniz
andycjw

Bu nlogn - n bit için, c'nin sabit olduğu n * c bitlerini kontrol eden yaklaşık logn yinelemelerini bekliyoruz.
Ron Warholic

Evet, bu 111001 ve 100111'de en basit vakalar olarak başarısız görünüyor. Eşit aralıklı 1'ler orta bit üzerinde ortalanmak zorunda değildir.
Dean J

Bu durumları doğru bir şekilde işler, 111001'in çift sayıda biti vardır, bu yüzden hemen 111 ve 001'e bölünür. 111'in tek sayıda biti olduğundan ve orta bit başarıyla döndüğü için.
Ron Warholic

1

Böyle bir şey buldum:

def IsSymetric(number):
    number = number.strip('0')

    if len(number) < 3:
        return False
    if len(number) % 2 == 0:
        return IsSymetric(number[1:]) or IsSymetric(number[0:len(number)-2])
    else:
        if number[len(number)//2] == '1':
            return True
        return IsSymetric(number[:(len(number)//2)]) or IsSymetric(number[len(number)//2+1:])
    return False

Bu ilham andycjw.

  1. Sıfırları kesin.
  2. Hatta iki alt dizeyi 0 - (len-2) (son karakteri atla) ve 1 - (len-1) 'den test edin (ilk karakteri atlayın)
  3. Eğer orta karakter daha başarılı olmasa bile. Else, ortadaki eleman olmadan ortadaki ipi bölün ve her iki parçayı da kontrol edin.

Karmaşıklığa gelince, her yinelemede ikiye böldüğümüz gibi O (nlogn) olabilir.

Umarım yardımcı olur.


N elemanlarıyla ilgili bir problemi N-1 elemanlarıyla 2 probleme dönüştürdüğünüz anlaşılıyor. Yarıya bölmek, N / 2 unsurları ile 2 probleme dönüştürmek anlamına gelir.
RHSeeger

Bu sadece eşit uzunluklar için geçerlidir. Eğer len 8 ise, algoritma uzunluk dizeleri oluşturur: 7, 7, 3, 3, 3, 3. Özyineleme ağacının yüksekliği 3'tür ve bu da lg (8) 'e eşittir.
Beku

1

Tamam, soruna bir bıçak daha atacağım. Ben 1'ler arasındaki mesafeleri depolamak için dengeli bir ikili ağaç kullanarak zaten tartışılanlara benzer bir O (n log (n)) algoritması kanıtlamak düşünüyorum. Bu yaklaşım, Adalet'in sorunu 1'ler arasındaki mesafeler listesine indirgeme konusundaki gözleminden esinlenmiştir.

Her bir düğüm 1'in konumunu depolayacak ve her bir kenar, her bir alt düğüm için bitişik 1'e olan mesafe ile etiketlenecek şekilde, 1'lerin konumu etrafında dengeli bir ikili ağaç oluşturmak için giriş dizesini tarayabilir miyiz? Örneğin:

10010001 gives the following tree

      3
     / \
  2 /   \ 3
   /     \
  0       7

Bu, O (n günlüğü (n)) içinde yapılabilir, çünkü n boyutunda bir dize için her ekleme en kötü durumda O (günlüğü (n)) alır.

Daha sonra sorun, herhangi bir düğümde, o düğümden sol alt öğe boyunca sağ alt yolla aynı mesafeye sahip bir yol olup olmadığını keşfetmek için ağacı aramaktır. Bu, her bir alt ağaçta yinelemeli olarak yapılabilir. Aramada iki alt ağacı birleştirirken, sol alt ağaçtaki yollarla olan mesafeleri sağdaki yollarla olan mesafelerle karşılaştırmalıyız. Bir alt ağaçtaki yol sayısı log (n) ile orantılı olacağından ve düğüm sayısı n olduğundan, bunun O (n log (n)) zamanında yapılabileceğine inanıyorum.

Bir şey mi kaçırdım?


"Bir alt ağaçtaki yol sayısı log (n) ile orantılı olacağından" Neden n değil? Genellikle bu umut verici bir yaklaşımdır.
sdcvvc

@sdcwc: n ile değil log (n) ile orantılıdır, çünkü dengeli bir ağaçta her alt ağaç düğümlerin yarısına sahiptir ve alt ağacın köküne giden yolların sayısı alt ağaçtaki düğüm sayısı ile aynıdır ( kök).
Jeremy Bourque

0

Bu eğlenceli bir sorun gibi görünüyordu, bu yüzden elimi denemeye karar verdim.

111000001'in ilk 3 tanesini bulacağını ve başarılı olacağını varsayıyorum. Esasen 1'i takip eden sıfır sayısı önemlidir, çünkü 0111000 tanımınıza göre 111000 ile aynıdır. Bir kez iki vaka bulduğunuzda, bir sonraki 1 üçlemeyi tamamlar.

İşte Python'da:

def find_three(bstring):
    print bstring
    dict = {}
    lastone = -1
    zerocount = 0
    for i in range(len(bstring)):
        if bstring[i] == '1':
            print i, ': 1'
            if lastone != -1:
                if(zerocount in dict):
                    dict[zerocount].append(lastone)
                    if len(dict[zerocount]) == 2:
                        dict[zerocount].append(i)
                        return True, dict
                else:
                    dict[zerocount] = [lastone]
            lastone = i
            zerocount = 0
        else:
            zerocount = zerocount + 1
    #this is really just book keeping, as we have failed at this point
    if lastone != -1:
        if(zerocount in dict):
            dict[zerocount].append(lastone)
        else:
            dict[zerocount] = [lastone]
    return False, dict

Bu ilk denemedir, bu yüzden daha temiz bir şekilde yazılabileceğinden eminim. Lütfen bu yöntemin başarısız olduğu durumları aşağıda listeleyin.


@ recursive, bunlar eşit aralıklı değildir.
James McMahon

Eşit aralıklarla ne demek istiyorsun? İndeks 0, 3 ve 6'ya bakın. Hepsi ve ikisini birbirinden ayırarak.
özyinelemeli

Anlıyorum, anladığım kadarıyla, sıfırlar yalnızca aralığa dahil edildi.
James McMahon

Soru, bunun çalışmadığı "1001011" den bahsediyor. Sorunun sorulmasından hemen sonra gönderilen ve bu ile aynı (diğer) sorunu çözen daha eski (şimdi silinmiş) bir cevap vardı. :-)
ShreevatsaR

Bugün işte buna bakıyordum ve Rob'un düzenlemesiyle ne anlama geldiğini anlamadım. Soruyu netlik için düzenledim. Onunla kolay zaman geçirdiğimde bir şeyleri kaçırdığımı bilmeliydim.
James McMahon

0

Bunun nlog (n) nedeninin aşağıdakilerden kaynaklandığını varsayıyorum:

  • Üçüzün başlangıcı olan 1'i bulmak için (n-2) karakteri kontrol etmeniz gerekir. Bu noktaya kadar bulamadıysanız, yapmayacaksınız (karakter n-1 ve n bir üçüz başlatamaz) (O (n))
  • Üçüzün parçası olan (birincisi tarafından başlatılan) ikinci 1'i bulmak için, m / 2 (m = nx; burada x, ilk 1 karakterinin ofsetidir) kontrol etmeniz gerekir. Bunun nedeni, ilk 1'in yarısına kadar ikinci 1'i bulamadıysanız, yapmayacaksınız ... çünkü üçüncü 1, ikinciyi tam olarak aynı mesafede olmalıdır. (O (log (n)))
  • O (1), endeksi bildiğinizden son 1'i bulmak için birinci ve ikinciyi bulduğunuz zaman olmalıdır.

Yani, n, log (n) ve 1 ... O (nlogn) var

Düzenleme: Hata! Beynim, n / 2'nin logn olduğunu belirledi ... ki belli ki (öğeler üzerindeki sayının iki katına çıkarılması iç döngüdeki yineleme sayısını hala iki katına çıkarıyor). Bu hala n ^ 2'de, sorunu çözmüyor. En azından bir kod yazmam lazım :)


Tcl'de uygulama

proc get-triplet {input} {
    for {set first 0} {$first < [string length $input]-2} {incr first} {
        if {[string index $input $first] != 1} {
            continue
        }
        set start [expr {$first + 1}]
        set end [expr {1+ $first + (([string length $input] - $first) /2)}]
        for {set second $start} {$second < $end} {incr second} {
            if {[string index $input $second] != 1} {
                continue
            }
            set last [expr {($second - $first) + $second}]
            if {[string index $input $last] == 1} {
                return [list $first $second $last]
            }
        }
    }
    return {}
}

get-triplet 10101      ;# 0 2 4
get-triplet 10111      ;# 0 2 4
get-triplet 11100000   ;# 0 1 2
get-triplet 0100100100 ;# 1 4 7

0

Sanırım sorunu çözmenin bir yolunu buldum, ancak resmi bir kanıt oluşturamıyorum. Yaptığım çözüm Java ile yazılmış ve kaç liste / dizi eriştiğini saymak için bir sayaç 'n' kullanıyor. Bu yüzden n doğruysa stringLength * log (stringLength) değerine eşit veya ondan küçük olmalıdır. 0 ila 2 ^ 22 sayıları için denedim ve işe yarıyor.

Giriş dizesini yineleyerek ve bir dizini tutan tüm dizinlerin bir listesini yaparak başlar. Bu sadece O (n).

Sonra dizinler listesinden bir firstIndex ve birinciden daha büyük bir secondIndex alır. Bu iki dizin, dizinler listesinde bulunduğundan, dizinleri içermelidir. Oradan thirdIndex hesaplanabilir. İnputString [thirdIndex] bir 1 ise, durur.

public static int testString(String input){
//n is the number of array/list accesses in the algorithm
int n=0;

//Put the indices of all the ones into a list, O(n)
ArrayList<Integer> ones = new ArrayList<Integer>();
for(int i=0;i<input.length();i++){
    if(input.charAt(i)=='1'){
        ones.add(i);
    }
}

//If less than three ones in list, just stop
if(ones.size()<3){
    return n;
}

int firstIndex, secondIndex, thirdIndex;
for(int x=0;x<ones.size()-2;x++){
    n++;
    firstIndex = ones.get(x);

    for(int y=x+1; y<ones.size()-1; y++){
        n++;
        secondIndex = ones.get(y);
        thirdIndex = secondIndex*2 - firstIndex;

        if(thirdIndex >= input.length()){
            break;
        }

        n++;
        if(input.charAt(thirdIndex) == '1'){
            //This case is satisfied if it has found three evenly spaced ones
            //System.out.println("This one => " + input);
            return n;
        }
    }
}

return n;

}

ek not: sayaç n, dizinler listesini oluşturmak için giriş dizesi üzerinde yinelendiğinde artırılmaz. Bu işlem O (n) şeklindedir, bu nedenle algoritma karmaşıklığı üzerinde bir etkisi olmayacaktır.


Hala iç içe iki O (n)
döngünüz

Dizin dizisi, giriş dizesiyle aynı boyutta değil. Bu benim gerçek bir kanıt yazmamı veya yanlış olduğunu kanıtlamamı zorlaştırıyor. Bu işi yapan temel matematiksel bir fikir olduğundan şüpheleniyorum.
Robert Parker

1
Bu sorunun hilesi algoritmanızın O (n ^ 2) olmasına rağmen, alabileceğiniz bir dizenin en kötü durumunun yalnızca O (nlogn) yinelemeleriyle sonuçlanacağıdır, aksi takdirde algoritmanızı kullanarak bir çözüm bulmuş olursunuz.
z -

2
2 ^ 22'ye kadar test etmek, karmaşıklığını gerçekten test etmez. 2 ^ 22 sadece 22 bite sahiptir, bu da N'nizin 22 olduğu anlamına gelir. N'nin birkaç milyon olduğu birkaç değer için deneyin.
Peter Recore

1
Bu algoritmayı yx cevabında verilen maksimum "kötü" dizelerden biriyle deneyin ve bunun bir algoritma olduğunu göreceksiniz O(n^2).
00'da Welbog

0

Sorunun içinde bir yol, faktörleri ve kaymayı düşünmektir.

Vites değiştirme ile, bir ve sıfırların dizesini kendi değiştirilmiş bir versiyonu ile karşılaştırırsınız. Daha sonra eşleşenleri alırsınız. Bu örneği ikiye kaydırın:

1010101010
  1010101010
------------
001010101000

Ortaya çıkan 1'ler (bitsel ANDed), iki ile eşit aralıklı olan tüm 1'leri temsil etmelidir. Aynı örnek üçe kaymıştır:

1010101010
   1010101010
-------------
0000000000000

Bu durumda, eşit aralıklarla yerleştirilmiş 1'ler yoktur.

Peki bu size ne anlatıyor? Sadece asal sayı olan vardiyaları test etmeniz gerekir. Örneğin, altı ayrı olan iki tane 1'iniz olduğunu varsayalım. Sadece 'iki' vardiyayı ve 'üç' vardiyayı test etmeniz gerekir (bunlar altıya bölündüğünden). Örneğin:

10000010 
  10000010 (Shift by two)
    10000010
      10000010 (We have a match)

10000010
   10000010 (Shift by three)
      10000010 (We have a match)

Bu yüzden kontrol etmeniz gereken tek vardiya 2,3,5,7,11,13 vb. Olacaktır.

Neredeyse çözüldü mü?

Sanırım bir çözüme daha yakınım. Temelde:

  1. Dizeyi 1'ler için tarayın. Her 1 nota için, konumunun bir modülünü aldıktan sonra kalantır. Modül, dizenin boyutunun 1 ila yarısı arasında değişir. Bunun nedeni, mümkün olan en büyük ayırma boyutunun dizenin yarısı olmasıdır. Bu O (n ^ 2) 'de yapılır. FAKAT. Yalnızca ana modüllerin kontrol edilmesi gerekir, böylece O (n ^ 2 / log (n))
  2. Modül / geriye kalanlar listesini önce en büyük modül sırasına göre sıralayın, bu O (n * log (n)) zamanında yapılabilir.
  3. Aynı olan üç ardışık modülü / geri kalanı arayın.
  4. Bir şekilde olanların konumunu alın!

Cevabın en büyük ipucu, en hızlı sıralama algoritmalarının O (n * log (n)) olduğunu düşünüyorum.

YANLIŞ

Adım 1, bir iş arkadaşınızın belirttiği gibi yanlıştır. 2,12 ve 102. pozisyonlarda 1'lerimiz varsa. Sonra 10'luk bir modül alarak, hepsinin aynı kalıntıları vardır ve yine de birbirlerinden eşit olarak ayrılmazlar! Afedersiniz.


Bu ilginç bir yaklaşım, tam bir çözüm bulursanız bize bildirin.
James McMahon

bir sayı k O (n) kez kaydırılır ve sonra O (n) kaydırma başına kontroller, bir sayı kaydırıyor olsanız bile O (n ^ 2) algoritması verir. Algoritmanızın birden fazla sayı kaydırması gerekir.
48'de ldog

0

İşte benim en iyi çabalarıma rağmen, kendilerini bir yayla sarmak gibi görünmeyecek bazı düşünceler. Yine de, bunlar birinin analizi için yararlı bir başlangıç ​​noktası olabilir.

Ben de bu cevabın önceki bir versiyonunda ben de dahil olmak üzere birçok insanın önerdiği yaklaşım olan önerilen çözümü şu şekilde düşünün. :)

  1. Baştaki ve sondaki sıfırları düzeltin.
  2. 1'leri arayan dizeyi tarayın.
  3. 1 bulunduğunda:
    1. Çözümün orta 1 olduğunu varsayalım.
    2. Her önceki 1 için, final 1'in beklenen konumunu hesaplamak için kaydedilmiş konumunu kullanın.
    3. Hesaplanan konum dizenin sonundan sonraysa, çözümün bir parçası olamaz, bu yüzden konumu aday listesinden bırakın.
    4. Çözümü kontrol edin.
  4. Çözüm bulunamazsa, geçerli 1'i aday listesine ekleyin.
  5. Başka 1 bulunana kadar tekrarlayın.

Şimdi, çözümü olmayan, aşağıdaki gibi giriş dizeleri dizelerini düşünün:

101
101001
1010010001
101001000100001
101001000100001000001

Genel olarak, bu, j 0 formundaki k dizelerinin ardından j için 1'den sıfırdan k-l'e kadar olan bir dizidir.

k=2  101
k=3  101001
k=4  1010010001
k=5  101001000100001
k=6  101001000100001000001

Alt dizelerin uzunluklarının 1, 2, 3 vb. Olduğuna dikkat edin. Bu nedenle, n nolu problem büyüklüğü, n = k (k + 1) / 2 olacak şekilde 1 ila k arasındaki uzunluklarda alt dizelere sahiptir.

k=2  n= 3  101
k=3  n= 6  101001
k=4  n=10  1010010001
k=5  n=15  101001000100001
k=6  n=21  101001000100001000001

K'nin de dikkate almamız gereken 1'lerin sayısını izlediğini unutmayın. 1'i her gördüğümüzde, şimdiye kadar görülen 1'lerin hepsini dikkate almamız gerektiğini unutmayın. Yani ikinci 1'i gördüğümüzde, sadece ilkini düşünüyoruz, üçüncü 1'i gördüğümüzde, ilk ikisini yeniden düşünüyoruz, dördüncü 1'i gördüğümüzde ilk üçünü tekrar gözden geçirmemiz gerekiyor vb. Algoritmanın sonunda, k (k-1) / 1'lerin 2 çiftini düşündük. Buna s.

k=2  n= 3  p= 1  101
k=3  n= 6  p= 3  101001
k=4  n=10  p= 6  1010010001
k=5  n=15  p=10  101001000100001
k=6  n=21  p=15  101001000100001000001

N ve p arasındaki ilişki n = p + k'dir.

Dizeden geçme işlemi O (n) zaman alır. 1 ile her karşılaşıldığında maksimum (k-1) karşılaştırması yapılır. N = k (k + 1) / 2 olduğundan, n> k ** 2, bu nedenle sqrt (n)> k. Bu bize O (n sqrt (n)) veya O (n ** 3/2) verir. Bununla birlikte, bu gerçekten sıkı bir sınır olmayabilir, çünkü karşılaştırma sayısı 1'den maksimum k'ya gider, tüm zaman boyunca k değildir. Ama bunun matematikte nasıl açıklanacağından emin değilim.

Hala O (n log (n)) değil. Ayrıca, bu girdilerin en kötü durum olduğunu kanıtlayamıyorum, ancak şüpheleniyorum. Bence 1'lerin daha yoğun bir ambalajı, sonunda daha seyrek bir ambalajla sonuçlanır.

Birisi hala yararlı bulabileceğinden, Perl'de bu çözüm için kodumu burada bulabilirsiniz:

#!/usr/bin/perl

# read input as first argument
my $s = $ARGV[0];

# validate the input
$s =~ /^[01]+$/ or die "invalid input string\n";

# strip leading and trailing 0's
$s =~ s/^0+//;
$s =~ s/0+$//;

# prime the position list with the first '1' at position 0
my @p = (0);

# start at position 1, which is the second character
my $i = 1;

print "the string is $s\n\n";

while ($i < length($s)) {
   if (substr($s, $i, 1) eq '1') {
      print "found '1' at position $i\n";
      my @t = ();
      # assuming this is the middle '1', go through the positions
      # of all the prior '1's and check whether there's another '1'
      # in the correct position after this '1' to make a solution
      while (scalar @p) {
         # $p is the position of the prior '1'
         my $p = shift @p;
         # $j is the corresponding position for the following '1'
         my $j = 2 * $i - $p;
         # if $j is off the end of the string then we don't need to
         # check $p anymore
         next if ($j >= length($s));
         print "checking positions $p, $i, $j\n";
         if (substr($s, $j, 1) eq '1') {
            print "\nsolution found at positions $p, $i, $j\n";
            exit 0;
         }
         # if $j isn't off the end of the string, keep $p for next time
         push @t, $p;
      }
      @p = @t;
      # add this '1' to the list of '1' positions
      push @p, $i;
   }
   $i++;
}

print "\nno solution found\n";

"Çözüm olmayan" diziniz yanlış; her 1'in indeksi 1, 3, 6, 10, 15 ... vb. üçgen sayı dizisidir ve aritmetik bir ilerleme oluşturan 6, 36 ve 66 sayılarını içerir.
Jason S

0

1'leri tararken konumlarını bir Listeye ekleyin. İkinci ve ardışık 1'leri eklerken, bunları listedeki her konumla karşılaştırın. Aralık, currentOne (ortada) - previousOne'da (solda) eşittir. Sağ taraftaki bit currentOne + aralığıdır. 1 ise, son.

Bunların listesi aralarındaki boşlukla ters orantılı olarak büyür. Basitçe ifade etmek gerekirse, 1'ler arasında çok fazla 0'ınız varsa (en kötü durumda olduğu gibi), bilinen 1'ler listeniz oldukça yavaş büyüyecektir.

using System;
using System.Collections.Generic;

namespace spacedOnes
{
    class Program
    {
        static int[] _bits = new int[8] {128, 64, 32, 16, 8, 4, 2, 1};

        static void Main(string[] args)
        {
            var bytes = new byte[4];
            var r = new Random();
            r.NextBytes(bytes);
            foreach (var b in bytes) {
                Console.Write(getByteString(b));
            }
            Console.WriteLine();
            var bitCount = bytes.Length * 8;
            var done = false;
            var onePositions = new List<int>();
            for (var i = 0; i < bitCount; i++)
            {
                if (isOne(bytes, i)) {
                    if (onePositions.Count > 0) {
                        foreach (var knownOne in onePositions) {
                            var spacing = i - knownOne;
                            var k = i + spacing;
                            if (k < bitCount && isOne(bytes, k)) {
                                Console.WriteLine("^".PadLeft(knownOne + 1) + "^".PadLeft(spacing) + "^".PadLeft(spacing));
                                done = true;
                                break;
                            }
                        }
                    }
                    if (done) {
                        break;
                    }
                    onePositions.Add(i);
                }
            }
            Console.ReadKey();
        }

        static String getByteString(byte b) {
            var s = new char[8];
            for (var i=0; i<s.Length; i++) {
                s[i] = ((b & _bits[i]) > 0 ? '1' : '0');
            }
            return new String(s);
        }

        static bool isOne(byte[] bytes, int i)
        {
            var byteIndex = i / 8;
            var bitIndex = i % 8;
            return (bytes[byteIndex] & _bits[bitIndex]) > 0;
        }
    }
}

0

Soruna 22. saf çözümü göndermeden önce bir yorum ekleyeceğimi düşündüm. Saf çözüm için, dizedeki 1'lerin sayısının en fazla O (log (n)) olduğunu, bunun yerine en fazla O (sqrt (n * log (n)) olduğunu göstermemiz gerekmez.

Çözücü:

def solve(Str):
    indexes=[]
    #O(n) setup
    for i in range(len(Str)):
        if Str[i]=='1':
            indexes.append(i)

    #O((number of 1's)^2) processing
    for i in range(len(indexes)):
        for j in range(i+1, len(indexes)):
                            indexDiff = indexes[j] - indexes[i]
            k=indexes[j] + indexDiff
            if k<len(Str) and Str[k]=='1':
                return True
    return False

Temel olarak flybywire'ın fikrine ve uygulamasına oldukça benzer, ancak geri gitmek yerine ileriye bakıyor.

Açgözlü String Builder:

#assumes final char hasn't been added, and would be a 1 
def lastCharMakesSolvable(Str):
    endIndex=len(Str)
    j=endIndex-1
    while j-(endIndex-j) >= 0:
        k=j-(endIndex-j)
        if k >= 0 and Str[k]=='1' and Str[j]=='1':
            return True
        j=j-1
    return False



def expandString(StartString=''):
    if lastCharMakesSolvable(StartString):
        return StartString + '0'
    return StartString + '1'

n=1
BaseStr=""
lastCount=0
while n<1000000:
    BaseStr=expandString(BaseStr)
    count=BaseStr.count('1')
    if count != lastCount:
        print(len(BaseStr), count)
    lastCount=count
    n=n+1

(Savunmamda hala 'python öğren' anlayış aşamasındayım)

Ayrıca, açgözlü dizelerin binadan potansiyel olarak yararlı çıktısı, 1'lerin sayısında 2'lik bir güce çarptıktan sonra oldukça tutarlı bir sıçrama var ... 2096'ya çarpmak için beklemek istemiyordum.

strlength   # of 1's
    1    1
    2    2
    4    3
    5    4
   10    5
   14    8
   28    9
   41    16
   82    17
  122    32
  244    33
  365    64
  730    65
 1094    128
 2188    129
 3281    256
 6562    257
 9842    512
19684    513
29525    1024

0

Matematiksel bir yaklaşım sunmaya çalışacağım. Bu bir sondan çok bir başlangıçtır, bu nedenle herhangi bir yardım, yorum ve hatta çelişki derinden takdir edilecektir. Ancak, bu yaklaşım kanıtlanırsa - algoritma dizede düz ileriye doğru bir aramadır.

  1. Sabit sayıda boşluk kve bir dize Sverildiğinde, k-aralıklı üçlünün aranması gerekir O(n)- Sadece her 0<=i<=(n-2k)olup olmadığını test ederiz S[i]==S[i+k]==S[i+2k]. Test sürüyor O(1)ve sabit olduğu n-kzamanlar yapıyoruz k, bu yüzden alıyor O(n-k)=O(n).

  2. Diyelim ki, sayısı ile 1aramamız gereken maksimum alan arasında bir Ters Oran var . Yani, eğer birçok kişi varsa 1, bir üçlü olmalı ve oldukça yoğun olmalıdır; Sadece birkaç kişi varsa 1, üçlü (eğer varsa) oldukça seyrek olabilir. Başka bir deyişle, eğer yeterli sayıda varsa 1, böyle bir üçlünün var olması gerektiğini kanıtlayabilirim - ve ne kadar çok 1var, daha yoğun bir üçlünün bulunması gerekir. Bu, Pigeonhole prensibi ile açıklanabilir - Bunu daha sonra detaylandırmayı umuyoruz.

  3. Diyelim ki aramam gereken kolası sayıda alan üzerinde bir üst sınır var. Şimdi, her 1yer S[i]biz için kontrol edilmesi gereken 1yer S[i-1]ve S[i+1], S[i-2]ve S[i+2]... S[i-k]ve S[i+k]. Bu alan O((k^2-k)/2)=O(k^2)her 1yer Snedeniyle - Gauss' Serisi Toplama Formula . Bu bölüm 1'den farklı olduğunu unutmayın - kSabit bir boşluk olarak değil, boşluk sayısı için bir üst sınır olarak yaşıyorum .

Kanıtlamamız gerek O(n*log(n)). Yani bunun k*(number of 1's)orantılı olduğunu göstermemiz gerekiyor log(n).

Bunu yapabiliyorsa, algoritma önemsiz - her biri için 1de Skimin endeksidir i, basitçe bakmak 1'mesafeye her iki tarafında yukarıya s k. Aynı mesafede iki tane bulunursa, geri dönün ive k. Yine, zor kısım kdoğruluğu bulmak ve kanıtlamak olacaktır .

Buradaki yorumlarınızı gerçekten takdir ediyorum. Şimdiye kadar başarı olmadan, beyaz tahtadaki ' ksayısı ile 1' arasındaki ilişkiyi bulmaya çalışıyorum .


0

Varsayım:

Yanlış, log (n) üst limit sayısı hakkında konuşmak

DÜZENLE:

Şimdi Cantor numaralarını kullanarak (doğru ise), setteki yoğunluğun (2/3) ^ Log_3 (n) (ne garip bir işlev) olduğunu ve kabul ediyorum ki, log (n) / n yoğunluğunun güçlü olduğunu kabul ediyorum.

Bu üst sınır ise, bu sorunu en az O (n * (3/2) ^ (log (n) / log (3))) zaman karmaşıklığında ve O ((3/2) ^ ( log (n) / log (3))) alan karmaşıklığı. (Adalet'in cevabını algoritma için kontrol edin)

Bu hala O (n ^ 2) 'den çok daha iyi

Bu işlev ((3/2) ^ (log (n) / log (3))) gerçekten ilk görüşte n * log (n) gibi görünür.

Bu formülü nasıl edindim?

Dizede Cantors numarası applaying.
Dize uzunluğunun 3 ^ p == n olduğunu varsayalım
. Cantor dizesinin oluşturulmasındaki her adımda, önceki sayısının 2 / 3'ünü tutarsınız. Bu p süreyi uygulayın.

Yani (n * ((2/3) ^ p)) -> (((3 ^ p)) * ((2/3) ^ p)) kalanlar ve sadeleştirmeden sonra 2 ^ p. Bu, 3 ^ p string -> (3/2) ^ p olanlarda 2 ^ p olanlar anlamına gelir. P = log (n) / log (3) yerine
geçin ve ((3/2) ^ (log (n) / log (3)) olsun


Yanlış: Cantor kümesinin yoğunluğu n ^ log_3 (2).
sdcvvc

0

O (n ^ 2) boşluklu basit bir O (n) çözümüne ne dersiniz? (Tüm bitsel operatörlerin O (1) 'de çalıştığı varsayımını kullanır.)

Algoritma temel olarak dört aşamada çalışır:

Aşama 1: Orijinal numaranızdaki her bit için, bunların ne kadar uzakta olduğunu öğrenin, ancak yalnızca bir yönü düşünün. (Tüm bitleri en az anlamlı bit yönünde değerlendirdim.)

Aşama 2: Girişteki bitlerin sırasını ters çevirin;

Aşama 3: 1. adımı tersine çevrilmiş girişte yeniden çalıştırın.

Aşama 4: Aşama 1 ve Aşama 3'ten alınan sonuçları karşılaştırın. Herhangi bir bit eşit olarak yukarıda VE aşağıda olacak şekilde bir isabet almamız gerekir.

Yukarıdaki algoritmada hiçbir adımın O (n) 'den daha uzun sürmediğini unutmayın. ^ _ ^

Ek bir avantaj olarak, bu algoritma HER sayıdan TÜM eşit aralıklı olanları bulacaktır. Örneğin, "0x0005" sonucunu alırsanız, 1 ve 3 BOTH biriminde eşit aralıklarla yerleştirilmiş olanlar olur

Gerçekten aşağıdaki kodu optimize deneyin vermedi, ama çalışıyor gibi görünüyor derlenebilir C # kodu.

using System;

namespace ThreeNumbers
{
    class Program
    {
        const int uint32Length = 32;

        static void Main(string[] args)
        {
            Console.Write("Please enter your integer: ");
            uint input = UInt32.Parse(Console.ReadLine());

            uint[] distancesLower = Distances(input);
            uint[] distancesHigher = Distances(Reverse(input));

            PrintHits(input, distancesLower, distancesHigher);
        }

        /// <summary>
        /// Returns an array showing how far the ones away from each bit in the input.  Only 
        /// considers ones at lower signifcant bits.  Index 0 represents the least significant bit 
        /// in the input.  Index 1 represents the second least significant bit in the input and so 
        /// on.  If a one is 3 away from the bit in question, then the third least significant bit 
        /// of the value will be sit.
        /// 
        /// As programed this algorithm needs: O(n) time, and O(n*log(n)) space.  
        /// (Where n is the number of bits in the input.)
        /// </summary>
        public static uint[] Distances(uint input)
        {
            uint[] distanceToOnes = new uint[uint32Length];
            uint result = 0;

            //Sets how far each bit is from other ones. Going in the direction of LSB to MSB
            for (uint bitIndex = 1, arrayIndex = 0; bitIndex != 0; bitIndex <<= 1, ++arrayIndex)
            {
                distanceToOnes[arrayIndex] = result;
                result <<= 1;

                if ((input & bitIndex) != 0)
                {
                    result |= 1;
                }
            }

            return distanceToOnes;
        }

        /// <summary>
        /// Reverses the bits in the input.
        /// 
        /// As programmed this algorithm needs O(n) time and O(n) space.  
        /// (Where n is the number of bits in the input.)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static uint Reverse(uint input)
        {
            uint reversedInput = 0;
            for (uint bitIndex = 1; bitIndex != 0; bitIndex <<= 1)
            {
                reversedInput <<= 1;
                reversedInput |= (uint)((input & bitIndex) != 0 ? 1 : 0);
            }

            return reversedInput;
        }

        /// <summary>
        /// Goes through each bit in the input, to check if there are any bits equally far away in 
        /// the distancesLower and distancesHigher
        /// </summary>
        public static void PrintHits(uint input, uint[] distancesLower, uint[] distancesHigher)
        {
            const int offset = uint32Length - 1;

            for (uint bitIndex = 1, arrayIndex = 0; bitIndex != 0; bitIndex <<= 1, ++arrayIndex)
            {
                //hits checks if any bits are equally spaced away from our current value
                bool isBitSet = (input & bitIndex) != 0;
                uint hits = distancesLower[arrayIndex] & distancesHigher[offset - arrayIndex];

                if (isBitSet && (hits != 0))
                {
                    Console.WriteLine(String.Format("The {0}-th LSB has hits 0x{1:x4} away", arrayIndex + 1, hits));
                }
            }
        }
    }
}

Birisi muhtemelen yeterince büyük bir sayı için O (1) 'de bitsel işlemlerin yapılamayacağını yorumlayacaktır. Haklısın. Bununla birlikte, toplama, çıkarma, çarpma veya bölme kullanan (kaydırılarak yapılamayan) her çözümün de bu problemi yaşayacağına inanıyorum.


0

Aşağıda bir çözüm var. Burada ve orada bazı küçük hatalar olabilir, ama fikir sağlamdır.

Düzenleme: Bu n * log (n) değil

PSEUDO KODU:

foreach character in the string
  if the character equals 1 {         
     if length cache > 0 { //we can skip the first one
        foreach location in the cache { //last in first out kind of order
           if ((currentlocation + (currentlocation - location)) < length string)
              if (string[(currentlocation + (currentlocation - location))] equals 1)
                 return found evenly spaced string
           else
              break;
        }
     }
     remember the location of this character in a some sort of cache.
  }

return didn't find evenly spaced string

C # kodu:

public static Boolean FindThreeEvenlySpacedOnes(String str) {
    List<int> cache = new List<int>();

    for (var x = 0; x < str.Length; x++) {
        if (str[x] == '1') {
            if (cache.Count > 0) {
                for (var i = cache.Count - 1; i > 0; i--) {
                    if ((x + (x - cache[i])) >= str.Length)
                        break;

                    if (str[(x + (x - cache[i]))] == '1')
                        return true;                            
                }
            }
            cache.Add(x);                    
        }
    }

    return false;
}

Nasıl çalışır:

iteration 1:
x
|
101101001
// the location of this 1 is stored in the cache

iteration 2:
 x
 | 
101101001

iteration 3:
a x b 
| | | 
101101001
//we retrieve location a out of the cache and then based on a 
//we calculate b and check if te string contains a 1 on location b

//and of course we store x in the cache because it's a 1

iteration 4:
  axb  
  |||  
101101001

a  x  b  
|  |  |  
101101001


iteration 5:
    x  
    |  
101101001

iteration 6:
   a x b 
   | | | 
101101001

  a  x  b 
  |  |  | 
101101001
//return found evenly spaced string

1
Algoritmanız çalışıyor, ancak O (n ^ 2) değerinden daha az olduğunu kanıtlamanız gerekiyor. Önemsiz analiz sizi O (n ^ 2) değerine götürür. Her 1 için, ondan önceki tüm 1'lerin üzerinden geçersiniz. Karmaşıklık işlevinin 1 + 2 + 3 + ... + (k / 2-1) = O (k ^ 2) olması [burada k, 1s sayısıdır].
Anna

Kontrol ettim ve gerçekten en kötü durum senaryosu O (n * log (n)) 'dan daha büyük
Niek H.

0

Açıkçası en azından üçüz demetini aynı anda kontrol etmemiz gerekiyor, bu yüzden kontrolleri bir şekilde sıkıştırmamız gerekiyor. Bir aday algoritmam var, ancak zaman karmaşıklığını analiz etmek benim yetenek zaman eşiğimin ötesinde.

Her düğümün üç çocuğu olan ve her düğümün yapraklarında toplam 1 sayısını içeren bir ağaç oluşturun. 1'ler üzerinde de bağlantılı bir liste oluşturun. Her düğüme kapsadığı aralıkla orantılı olarak izin verilen bir maliyet atayın. Her bir düğümde geçirdiğimiz süre bütçe dahilinde olduğu sürece, bir O (n lg n) algoritmamız olacaktır.

-

Kökten başlayın. Aşağıdaki toplam 1 sayısının karesi izin verilen maliyetinden düşükse, saf algoritmayı uygulayın. Aksi takdirde çocuklarına geri ödeme.

Şimdi ya bütçe dahilinde geri döndük ya da çocuklardan birinin içinde tamamen geçerli üçüz olmadığını biliyoruz. Bu nedenle düğümler arası üçüzleri kontrol etmeliyiz.

Şimdi işler inanılmaz derecede dağınık. Aslında menzili sınırlandırırken potansiyel çocuk setlerini tekrarlamak istiyoruz. Aralık, naif algoritmanın bütçe altında çalışmasına yetecek kadar kısıtlandığında, bunu yaparsınız. Bunu uygulamanın tadını çıkarın, çünkü sıkıcı olacağını garanti ediyorum. Bir düzine dava var.

-

Algoritmanın çalışacağını düşünmemizin nedeni, geçerli üçüzleri olmayan dizilerin 1'lerin demetleri ve 0'ların sürüleri arasında değiştiği görülüyor. Yakındaki arama alanını etkili bir şekilde böler ve ağaç bu bölünmeyi taklit eder.

Algoritmanın çalışma süresi hiç belli değil. Dizinin önemsiz özelliklerine dayanır. 1'ler gerçekten seyrek ise, saf algoritma bütçe altında çalışacaktır. 1'ler yoğunsa, hemen bir eşleşme bulunmalıdır. Ancak yoğunluk 'doğru' ise (örneğin, taban 3'te '2' rakamı olmayan konumlarda tüm bitleri ayarlayarak elde edebileceğiniz ~ n ^ 0.63 yakınında), işe yarayıp yaramayacağını bilmiyorum. Bölme etkisinin yeterince güçlü olduğunu kanıtlamanız gerekir.


0

Burada teorik bir cevap yok, ama çalışma zamanı davranışını k ve n'nin bir fonksiyonu olarak keşfetmek için hızlı bir Java programı yazdım, burada n toplam bit uzunluğu ve k 1'lerin sayısıdır. En kötü durumda O (k ^ 2) gerektirecek olsa bile, bit pozisyonlarının tüm çiftlerini kontrol eden ve 3. biti arayan "normal" algoritmanın olduğunu söyleyen birkaç cevaplayıcı ile beraberim. çünkü en kötü durum seyrek bit dizgileri gerektirir, O (n ln n).

Her neyse, aşağıda program. Sabit n için çok sayıda NTRIALS denemesini yürüten ve belirlenebilir sınırlar arasında tek yoğunluklu sınırlandırılmış Bernoulli süreçlerini kullanarak rastgele bir dizi k-değeri için bit setleri üreten bir Monte-Carlo tarzı programdır ve çalışma süresini kaydeder CPU zamanındaki DEĞİL adımlarla ölçülen, eşit aralıklı olanların üçlüsünü bulma veya bulamama. N = 64, 256, 1024, 4096, 16384 * (hala çalışıyor) için çalıştırdım, önce hangi k-değerlerinin en uzun çalışma süresini aldığını görmek için 500000 deneme ile bir test çalışması, daha sonra daralmış olan 5000000 deneme ile başka bir test yoğunluk odaklanarak bu değerlerin nasıl göründüğünü görebilirsiniz. En uzun çalışma süreleri çok seyrek yoğunlukta gerçekleşir (örneğin n = 4096 için çalışma süresi zirveleri k = 16-64 aralığındadır, ortalama çalışma süresi için 4212 adımda hafif bir zirve @ k = 31, max çalışma zamanı 5101 adımda @ k = 58). Görünüşe göre en kötü O (k ^ 2) adımı, 1'in konum indekslerini bulmak için bit dizisini taradığınız O (n) adımından daha büyük hale gelmek için son derece büyük N değerleri alacaktır.

package com.example.math;

import java.io.PrintStream;
import java.util.BitSet;
import java.util.Random;

public class EvenlySpacedOnesTest {
    static public class StatisticalSummary
    {
        private int n=0;
        private double min=Double.POSITIVE_INFINITY;
        private double max=Double.NEGATIVE_INFINITY;
        private double mean=0;
        private double S=0;

        public StatisticalSummary() {}
        public void add(double x) {
            min = Math.min(min, x);
            max = Math.max(max, x);
            ++n;
            double newMean = mean + (x-mean)/n;
            S += (x-newMean)*(x-mean);
            // this algorithm for mean,std dev based on Knuth TAOCP vol 2
            mean = newMean;
        }
        public double getMax() { return (n>0)?max:Double.NaN; }
        public double getMin() { return (n>0)?min:Double.NaN; }
        public int getCount() { return n; }
        public double getMean() { return (n>0)?mean:Double.NaN; }
        public double getStdDev() { return (n>0)?Math.sqrt(S/n):Double.NaN; } 
        // some may quibble and use n-1 for sample std dev vs population std dev    
        public static void printOut(PrintStream ps, StatisticalSummary[] statistics) {
            for (int i = 0; i < statistics.length; ++i)
            {
                StatisticalSummary summary = statistics[i];
                ps.printf("%d\t%d\t%.0f\t%.0f\t%.5f\t%.5f\n",
                        i,
                        summary.getCount(),
                        summary.getMin(),
                        summary.getMax(),
                        summary.getMean(),
                        summary.getStdDev());
            }
        }
    }

    public interface RandomBernoulliProcess // see http://en.wikipedia.org/wiki/Bernoulli_process
    {
        public void setProbability(double d);
        public boolean getNextBoolean();
    }

    static public class Bernoulli implements RandomBernoulliProcess
    {
        final private Random r = new Random();
        private double p = 0.5;
        public boolean getNextBoolean() { return r.nextDouble() < p; }
        public void setProbability(double d) { p = d; }
    }   
    static public class TestResult {
        final public int k;
        final public int nsteps;
        public TestResult(int k, int nsteps) { this.k=k; this.nsteps=nsteps; } 
    }

    ////////////
    final private int n;
    final private int ntrials;
    final private double pmin;
    final private double pmax;
    final private Random random = new Random();
    final private Bernoulli bernoulli = new Bernoulli();
    final private BitSet bits;
    public EvenlySpacedOnesTest(int n, int ntrials, double pmin, double pmax) {
        this.n=n; this.ntrials=ntrials; this.pmin=pmin; this.pmax=pmax;
        this.bits = new BitSet(n);
    }

    /*
     * generate random bit string
     */
    private int generateBits()
    {
        int k = 0; // # of 1's
        for (int i = 0; i < n; ++i)
        {
            boolean b = bernoulli.getNextBoolean();
            this.bits.set(i, b);
            if (b) ++k;
        }
        return k;
    }

    private int findEvenlySpacedOnes(int k, int[] pos) 
    {
        int[] bitPosition = new int[k];
        for (int i = 0, j = 0; i < n; ++i)
        {
            if (this.bits.get(i))
            {
                bitPosition[j++] = i;
            }
        }
        int nsteps = n; // first, it takes N operations to find the bit positions.
        boolean found = false;
        if (k >= 3) // don't bother doing anything if there are less than 3 ones. :(
        {       
            int lastBitSetPosition = bitPosition[k-1];
            for (int j1 = 0; !found && j1 < k; ++j1)
            {
                pos[0] = bitPosition[j1];
                for (int j2 = j1+1; !found && j2 < k; ++j2)
                {
                    pos[1] = bitPosition[j2];

                    ++nsteps;
                    pos[2] = 2*pos[1]-pos[0];
                    // calculate 3rd bit index that might be set;
                    // the other two indices point to bits that are set
                    if (pos[2] > lastBitSetPosition)
                        break;
                    // loop inner loop until we go out of bounds

                    found = this.bits.get(pos[2]);
                    // we're done if we find a third 1!
                }
            }
        }
        if (!found)
            pos[0]=-1;
        return nsteps;
    }

    /*
     * run an algorithm that finds evenly spaced ones and returns # of steps.
     */
    public TestResult run()
    {
        bernoulli.setProbability(pmin + (pmax-pmin)*random.nextDouble());
        // probability of bernoulli process is randomly distributed between pmin and pmax

        // generate bit string.
        int k = generateBits();
        int[] pos = new int[3];
        int nsteps = findEvenlySpacedOnes(k, pos);
        return new TestResult(k, nsteps); 
    }

    public static void main(String[] args)
    {
        int n;
        int ntrials;
        double pmin = 0, pmax = 1;
        try {
            n = Integer.parseInt(args[0]);
            ntrials = Integer.parseInt(args[1]);
            if (args.length >= 3)
                pmin = Double.parseDouble(args[2]);
            if (args.length >= 4)
                pmax = Double.parseDouble(args[3]);
        }
        catch (Exception e)
        {
            System.out.println("usage: EvenlySpacedOnesTest N NTRIALS [pmin [pmax]]");
            System.exit(0);
            return; // make the compiler happy
        }

        final StatisticalSummary[] statistics;
        statistics=new StatisticalSummary[n+1];
        for (int i = 0; i <= n; ++i)
        {
            statistics[i] = new StatisticalSummary();
        }

        EvenlySpacedOnesTest test = new EvenlySpacedOnesTest(n, ntrials, pmin, pmax);
        int printInterval=100000;
        int nextPrint = printInterval;
        for (int i = 0; i < ntrials; ++i)
        {
            TestResult result = test.run();
            statistics[result.k].add(result.nsteps);
            if (i == nextPrint)
            {
                System.err.println(i);
                nextPrint += printInterval;
            }
        }
        StatisticalSummary.printOut(System.out, statistics);
    }
}

0
# <algorithm>
def contains_evenly_spaced?(input)
  return false if input.size < 3
  one_indices = []
  input.each_with_index do |digit, index|
    next if digit == 0
    one_indices << index
  end
  return false if one_indices.size < 3
  previous_indexes = []
  one_indices.each do |index|
    if !previous_indexes.empty?
      previous_indexes.each do |previous_index|
        multiple = index - previous_index
        success_index = index + multiple
        return true if input[success_index] == 1
      end
    end
    previous_indexes << index
  end
  return false
end
# </algorithm>

def parse_input(input)
  input.chars.map { |c| c.to_i }
end

Milyonlarca basamaklı en kötü senaryolarda sorun yaşıyorum. Fuzzing /dev/urandomaslında O (n) verir, ama biliyorum en kötü durum bundan daha kötü. Ne kadar kötü olduğunu söyleyemem. Küçük için n, onun etrafında değerlerde bulmak için Önemsiz 3*n*log(n)ama bu özel sorunun büyümesinin başka sırayla gelenler ayırt etmek şaşırtıcı zor.

En kötü durumda girdiler üzerinde çalışan herkes, yüz binden daha uzun bir dize üretebilir mi?


Cevabımda işaret ettiğim gibi, herhangi bir sayıda basamaktan kötü (en kötü durumda olmasa da) dizeler oluşturmak kolaydır: 1'leri üçlü gösterimlerinde "1" içermeyen p konumlarına (yani, 2, 6, 8, 18, 20, 24, 26, 54, 56, 60 ... pozisyonlarına bakınız: Research.att.com/~njas/sequences/… 'deki formüllere bakınız). 3 ^ 13 ≈ 1 milyon için bunun 2 ^ 13 ≈ 8000 1s değeri vardır. Bu tür dizelerde çalışma süresi ≈ n ^ (1.26) olacaktır - bu tür küçük n için O (n log n) 'den ayırt edilmesi zor olabilir. Deneyin ve görün.
ShreevatsaR


-3

Bu bir çözüm olabilir mi? Ben ', O (nlogn) olup olmadığından emin değilim ama bence O (n²)' den daha iyi çünkü üçlü bulmanın tek yolu asal sayı dağılımı olacaktır.

Iyileştirilmesi için oda var, ikinci bulundu 1 sonraki ilk 1 olabilir. Ayrıca hiçbir hata kontrol.

#include <iostream>

#include <string>

int findIt(std::string toCheck) {
    for (int i=0; i<toCheck.length(); i++) {
        if (toCheck[i]=='1') {
            std::cout << i << ": " << toCheck[i];
            for (int j = i+1; j<toCheck.length(); j++) {
                if (toCheck[j]=='1' && toCheck[(i+2*(j-i))] == '1') {
                    std::cout << ", " << j << ":" << toCheck[j] << ", " << (i+2*(j-i)) << ":" << toCheck[(i+2*(j-i))] << "    found" << std::endl;
                    return 0;
                }
            }
        }
    }
    return -1;
}

int main (int agrc, char* args[]) {
    std::string toCheck("1001011");
    findIt(toCheck);
    std::cin.get();
    return 0;
}

1
Teknik olarak bu O (n ^ 2) 'dir. Ortalama döngü, her çalıştırıldığında n'nin yarısından fazlasını yineleyecektir. Böylece O (n * (n / 2)) olarak yazılabilir ve bu O (n ^ 2) ile basitleştirilebilir
Robert Parker

Hm, haklısın gibi görünüyor. Bu basit bir sorun değil, sadece 1 (O) alır, O (logn) karmaşıklığı ile daha fazla arama / karşılaştırma için fazla yer bulmak için.
DaClown

-3

Bu algoritmanın O (n log n) karmaşıklığı (C ++, DevStudio 2k5) olduğunu düşünüyorum. Şimdi, karmaşıklığını belirlemek için bir algoritmanın nasıl analiz edileceğinin ayrıntılarını bilmiyorum, bu yüzden koda bazı metrik toplama bilgileri ekledim. Kod, herhangi bir giriş için 1'ler ve 0'lar dizisi üzerinde yapılan test sayısını sayar (umarım, algoritmanın bir topunu yapmadım). Gerçek test sayısını O değeriyle karşılaştırabilir ve bir korelasyon olup olmadığını görebiliriz.

#include <iostream>
using namespace std;

bool HasEvenBits (string &sequence, int &num_compares)
{
  bool
    has_even_bits = false;

  num_compares = 0;

  for (unsigned i = 1 ; i <= (sequence.length () - 1) / 2 ; ++i)
  {
    for (unsigned j = 0 ; j < sequence.length () - 2 * i ; ++j)
    {
      ++num_compares;
      if (sequence [j] == '1' && sequence [j + i] == '1' && sequence [j + i * 2] == '1')
      {
        has_even_bits = true;
        // we could 'break' here, but I want to know the worst case scenario so keep going to the end
      }
    }
  }

  return has_even_bits;
}

int main ()
{
  int
    count;

  string
    input = "111";

  for (int i = 3 ; i < 32 ; ++i)
  {
    HasEvenBits (input, count);
    cout << i << ", " << count << endl;
    input += "0";
  }
}

Bu program, 32 karaktere kadar her dize uzunluğu için test sayısını çıkarır. İşte sonuçlar:

 n  Tests  n log (n)
=====================
 3     1     1.43
 4     2     2.41
 5     4     3.49
 6     6     4.67
 7     9     5.92
 8    12     7.22
 9    16     8.59
10    20    10.00
11    25    11.46
12    30    12.95
13    36    14.48
14    42    16.05
15    49    17.64
16    56    19.27
17    64    20.92
18    72    22.59
19    81    24.30
20    90    26.02
21   100    27.77
22   110    29.53
23   121    31.32
24   132    33.13
25   144    34.95
26   156    36.79
27   169    38.65
28   182    40.52
29   196    42.41
30   210    44.31
31   225    46.23

'N log n' değerlerini de ekledim. İki sonuç arasında bir korelasyon görmek için bunları seçtiğiniz grafik aracını kullanarak çizin. Bu analiz n'nin tüm değerlerini kapsıyor mu? Bilmiyorum.


Mükemmel bir korelasyon değil, katılıyorum. Bununla birlikte, eğri n log n'ye n ^ 2'den daha yakındır.
Skizz

3
Giriş boyutunu bir milyon veya daha fazla pompalamayı deneyin. Küçük girişlerde eğri, giriş boyutu pompalandığında açıkça daha iyi olan algoritma eğrilerine benzemektedir.
Nick Larsen

İç taraf dış kenar ile sınırlanmış bir halka için bir çift, hala O (n ^ 2) olan karmaşık bir şekil oluşturur. Hepsini (i, j) düşünün ki, [0, n] 'de i ve [0, n-2 * i]' de j, bir üçgene sahipsiniz ve bir üçgenin alanı ikinci dereceden bir eğilim gösterir.
Matthieu M.Eki

Kesin olmak gerekirse, Testler = (n ^ 2-2n) / 4 bile n için; belli ki ikinci dereceden.
Büyükbaba
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.