SORU
14 AĞUSTOS 2013, ÇARŞAMBA


Keşfetmek uzun desenleri

Numaraları sıralı bir listesini göz önüne alındığında, art arda gelen unsurları arasındaki farkları geometrik olarak arttığı uzun subsequence bulmak istiyorum. Eğer liste bu kadar

 1, 2, 3, 4, 7, 15, 27, 30, 31, 81

sonra subsequence 1, 3, 7, 15, 31. Alternatif olarak = 3 ve k = 2 5, 11, 23, 47 subsequence olan 1, 2, 5, 6, 11, 15, 23, 41, 47 düşünün.

Bu O içinde çözülür(n2) zaman? N listesi sıfırdır.

Farklılıklar ilerlemesi bulunduğu genel durum hem de ilgimi çektiak,ak2,ak3vb., burada her ikisi debirvektam sayılar ve özel durumdabirFark ilerlemesi yani = 1,k,k2,k3vb.

CEVAP
17 AĞUSTOS 2013, CUMARTESİ


Güncelleme

O (^2 M N) ve O bellek ihtiyacı(M N) ortalama gereken algoritma bir iyileştirme yaptım. Ağırlıklı olarak protokol aşağıda açıklanan, ancak olası faktörler,değil farklılık D) hesaplamak için bir tablo ben önceden aynı. Bu tablo, M=10^7 inşa edilecek bir saniyeden daha kısa sürer.

N=10^5 farklı rasgele tamsayı öğeleri çözmek için 10minutes daha az alır C bir uygulama yaptım.

Burada kaynak C kod:- O3 -o findgeo findgeo.gcc bunu çalıştırmak İçin sadece: c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include <time.h>

struct Factor {
    int a;
    int k;
    struct Factor *next;
};

struct Factor *factors = 0;
int factorsL=0;

void ConstructFactors(int R) {
    int a,k,C;
    int R2;
    struct Factor *f;
    float seconds;
    clock_t end;
    clock_t start = clock();

    if (factors) free(factors);
    factors = malloc (sizeof(struct Factor) *((R>>1)   1));
    R2 = R>>1 ;
    for (a=0;a<=R2;a  ) {
        factors[a].a= a;
        factors[a].k=1;
        factors[a].next=NULL;
    }
    factorsL=R2 1;
    R2 = floor(sqrt(R));
    for (k=2; k<=R2; k  ) {
        a=1;
        C=a*k*(k 1);
        while (C<R) {
            C >>= 1;
            f=malloc(sizeof(struct Factor));
            *f=factors[C];
            factors[C].a=a;
            factors[C].k=k;
            factors[C].next=f;
            a  ;
            C=a*k*(k 1);
        }
    }

    end = clock();
    seconds = (float)(end - start) / CLOCKS_PER_SEC;
    printf("Construct Table: %f\n",seconds);
}

void DestructFactors() {
    int i;
    struct Factor *f;
    for (i=0;i<factorsL;i  ) {
        while (factors[i].next) {
            f=factors[i].next->next;
            free(factors[i].next);
            factors[i].next=f;
        }
    }
    free(factors);
    factors=NULL;
    factorsL=0;
}

int ipow(int base, int exp)
{
    int result = 1;
    while (exp)
    {
        if (exp & 1)
            result *= base;
        exp >>= 1;
        base *= base;
    }

    return result;
}

void findGeo(int **bestSolution, int *bestSolutionL,int *Arr, int L) {
    int i,j,D;
    int mustExistToBeBetter;
    int R=Arr[L-1]-Arr[0];
    int *possibleSolution;
    int possibleSolutionL=0;
    int exp;
    int NextVal;
    int idx;
    int kMax,aMax;
    float seconds;
    clock_t end;
    clock_t start = clock();


    kMax = floor(sqrt(R));
    aMax = floor(R/2);
    ConstructFactors(R);
    *bestSolutionL=2;
    *bestSolution=malloc(0);

    possibleSolution = malloc(sizeof(int)*(R 1));

    struct Factor *f;
    int *H=malloc(sizeof(int)*(R 1));
    memset(H,0, sizeof(int)*(R 1));
    for (i=0;i<L;i  ) {
        H[ Arr[i]-Arr[0] ]=1;
    }
    for (i=0; i<L-2;i  ) {
        for (j=i 2; j<L; j  ) {
            D=Arr[j]-Arr[i];
            if (D & 1) continue;
            f = factors   (D >>1);
            while (f) {
                idx=Arr[i]   f->a * f->k  - Arr[0];
                if ((f->k <= kMax)&& (f->a<aMax)&&(idx<=R)&&H[idx]) {
                    if (f->k ==1) {
                        mustExistToBeBetter = Arr[i]   f->a * (*bestSolutionL);
                    } else {
                        mustExistToBeBetter = Arr[i]   f->a * f->k * (ipow(f->k,*bestSolutionL) - 1)/(f->k-1);
                    }
                    if (mustExistToBeBetter< Arr[L-1] 1) {
                        idx=  floor(mustExistToBeBetter - Arr[0]);
                    } else {
                        idx = R 1;
                    }
                    if ((idx<=R)&&H[idx]) {
                        possibleSolution[0]=Arr[i];
                        possibleSolution[1]=Arr[i]   f->a*f->k;
                        possibleSolution[2]=Arr[j];
                        possibleSolutionL=3;
                        exp = f->k * f->k * f->k;
                        NextVal = Arr[j]   f->a * exp;
                        idx=NextVal - Arr[0];
                        while ( (idx<=R) && H[idx]) {
                            possibleSolution[possibleSolutionL]=NextVal;
                            possibleSolutionL  ;
                            exp = exp * f->k;
                            NextVal = NextVal   f->a * exp;
                            idx=NextVal - Arr[0];
                        }

                        if (possibleSolutionL > *bestSolutionL) {
                            free(*bestSolution);
                            *bestSolution = possibleSolution;
                            possibleSolution = malloc(sizeof(int)*(R 1));
                            *bestSolutionL=possibleSolutionL;
                            kMax= floor( pow (R, 1/ (*bestSolutionL) ));
                            aMax= floor(R /  (*bestSolutionL));
                        }
                    }
                }
                f=f->next;
            }
        }
    }

    if (*bestSolutionL == 2) {
        free(*bestSolution);
        possibleSolutionL=0;
        for (i=0; (i<2)&&(i<L); i   ) {
            possibleSolution[possibleSolutionL]=Arr[i];
            possibleSolutionL  ;
        }
        *bestSolution = possibleSolution;
        *bestSolutionL=possibleSolutionL;
    } else {
        free(possibleSolution);
    }
    DestructFactors();
    free(H);

    end = clock();
    seconds = (float)(end - start) / CLOCKS_PER_SEC;
    printf("findGeo: %f\n",seconds);
}

int compareInt (const void * a, const void * b)
{
    return *(int *)a - *(int *)b;
}

int main(void) {
    int N=100000;
    int R=10000000;
    int *A = malloc(sizeof(int)*N);
    int *Sol;
    int SolL;
    int i;


    int *S=malloc(sizeof(int)*R);
    for (i=0;i<R;i  ) S[i]=i 1;

    for (i=0;i<N;i  ) {
        int r = rand() % (R-i);
        A[i]=S[r];
        S[r]=S[R-i-1];
    }

    free(S);
    qsort(A,N,sizeof(int),compareInt);

/*
    int step = floor(R/N);
    A[0]=1;
    for (i=1;i<N;i  ) {
        A[i]=A[i-1] step;
    }
*/

    findGeo(&Sol,&SolL,A,N);

    printf("[");
    for (i=0;i<SolL;i  ) {
        if (i>0) printf(",");
        printf("%d",Sol[i]);
    }
    printf("]\n");
    printf("Size: %d\n",SolL);

    free(Sol);
    free(A);
    return EXIT_SUCCESS;
}

Gösteri

Ben önerilen bu algoritma eşit dağılımlı rastgele bir dizi için ortalama O(N`2 M) olduğunu göstermek için çalışacağız. Bir matematikçi değilim ve gösterilere bu tür, lütfen beni gördüğünüz herhangi bir hatayı düzeltmek için ücretsiz doldurmak, bunu yapmak için kullanılan değilim.

4 girintili döngüler vardır, iki ilkleri^2 N faktör vardır. M Olası faktörleri tablo) hesaplanması için.

Üçüncü döngü sadece bir kez her çift için ortalama olarak yürütülür. Bu denetleme öncesi hesaplanan faktörler tablo boyutunu görebilirsiniz. Onun büyüklüğü N -^ M . ınf. Her çift için ortalama adımları yani M/M=1.

Kanıtı olduğunu ileri döngü kontrol etmek olur. (İyi yapılmış dizileri erişir, bir çift için daha az ya da O(N^2) ' ler eşittir.

Bunu göstermek için, iki durum dikkate alacağım: M^< . M ilk dizinin en büyük fark Nerede ~= N. M burada N ve diğer: M= S(n)-S(1).

İlk durumda, (M^< . N) olasılık bulmak bir tesadüf mü p=N/m başlangıç sırası olmalı denk ikinci ve b 1 öğe nerede b uzunluğu en iyi dizisi şu ana kadar. Döngü N^2*(N/M)^2 kez girin. Ve bu dizi ortalama uzunluğu (sonsuz bir dizi düşünürken) p/(1-p) = N/(M-N). Döngü yürütülür bu kez toplam sayı N^2 * (N/M)^2 * N/(M-N). Ve bu 0'a yakın M^ zaman< . Ne zaman~=N. M N. sorun burada

Şimdi b şimdiye kadar en iyi dizisi uzunluğu olduğunu düşünün bu durumda düşünün sağlar. Durum A=k=1, Daha sonra sırası gerekir başlamadan önce N-b, sayı dizileri olacak N-b ve katı olacak gitmek için döngü olacak en fazla (N-b)*b.

Bir^ İçin . 1 ve k=1 d M/N nerede (N-A*b/d)*b tahmin edebilir (sayılar arasındaki ortalama mesafe). Eğer 1'den tüm A/b dN için ekledik, sonra da bir üst sınırı görüyoruz:

\sum_{A=1}^{dN/b}\left ( N-\frac{Ab}{d} \right )b=\frac{N^2d}{2}

K^ hallerde . =2, gördüğümüz dizi gerekir başlamadan önce N-A*k^b/d, Böylece döngü girin ortalama A*k^b/d)*b ve ekleme Olarak 1 ila dN/k^b, verir bir limit

\sum_{A=1}^{dN/k^b}\left ( N-\frac{Ak^b}{d} \right )b=\frac{bN^2d}{2k^b}

Burada, en kötü ihtimalle b minimum olmasıdır. En az dizi düşünüyoruz, çünkü b çok kötü bir durumda düşünün sağlar= 2 sonuç olarak verilen bir k için 4 döngü için geçen sayısı daha az olacak

\frac{dN^2}{k^2} .

Ve eğer k sonsuz 2 tüm eklersek olacaktır:

\sum_{k=2}^{\infty } \frac{dN^2}{k^2} = dN^2 \left ( \frac{\pi ^2}{6}  -1\right )

Bu yüzden k için tüm geçişleri ekleme=1 ve k>=2, en fazla

\frac{N^2d}{2}  N^2d \left ( \frac{\pi ^2}{6}  -1\right ) = N^2d\left ( \frac{\pi ^2}{6} - \frac{1}{2}\right ) \simeq 1.45N^2d

D=M/N=1/p unutmayın.

İki sınırları var, bu yüzden, zaman sonsuz giden Bir d=1/M=1/N gider ve sonsuz gider d sonsuz gittiğinde diğer p. O yüzden bizim sınırı hem de en az ve en kötü ihtimalle her iki equetions geçerken. Yani biz bu denklemi çözmek:

 N^2d\left ( \frac{\pi ^2}{6} - \frac{1}{2}\right ) = N^2\left ( \frac{N}{M} \right )^2\frac{N}{M-N} =N^2\left ( \frac{1}{d} \right )^2\frac{1}{d-1}

maksimum zaman=1.353 d olduğunu görüyoruz

Dördüncü işlenir 1.55 az^2 N kez toplam döngüler ortaya konulmuştur.

Tabii ki, bu ortalama durum için. Kötü durumda değilim bulur bir yolunu oluşturmak serisi olan ileri döngü daha yüksek O(N^2), ve ben inanıyorum ki onlar yok, ama ben bir matematikçi kanıtlamak.

Eski Cevap

Burada M dizinin ilk ve son elemanı arasındaki fark nerede O ortalama((n^2)*cube_root(M)) bir çözüm. Ve O hafıza gereksinimleri(M N).

1.- Eğer öyle bir şey varsa Eğer ilk dizi ben de var ve eğer yanlış bir dizi uzunluğu M O M[ı - S[0]]=H doğru inşa.

2.- Dizi Nin her çift için[j], S[i]:

2.1 eğer olası bir çözüm birinci ve üçüncü elemanları olup olmadığını Kontrol edin. Bunu yapmak için, olası Bir denklem S(i) karşılayan çift K) = S(j)^2 AK AK hesaplamak. this SO question Bu sorunu çözmek için nasıl görmek için kontrol edin. İkinci unsur mevcut kontrol: [i] S*K

2.2 Onay da bir pozisyon daha var ki en iyi çözüm bu unsur mevcut. Örneğin, en iyi çözüm bu kadar şimdi 4 element uzun süre sonra kontrol diye bir eleman A[j]*K*K^2*K^3*K^4

2.1 ve 2.2 2.3 doğruysa, bu dizi ve şimdi geçen o uzun kadar bestSolution olarak ayarlanır nasıl yineleme.

Burada javascript: kodu

function getAKs(A) {
    if (A / 2 != Math.floor(A / 2)) return [];
    var solution = [];
    var i;
    var SR3 = Math.pow(A, 1 / 3);
    for (i = 1; i <= SR3; i  ) {
        var B, C;
        C = i;
        B = A / (C * (C   1));
        if (B == Math.floor(B)) {
            solution.push([B, C]);
        }

        B = i;
        C = (-1   Math.sqrt(1   4 * A / B)) / 2;
        if (C == Math.floor(C)) {
            solution.push([B, C]);
        }
    }

    return solution;
}

function getBestGeometricSequence(S) {
    var i, j, k;

    var bestSolution = [];

    var H = Array(S[S.length-1]-S[0]);
    for (i = 0; i < S.length; i  ) H[S[i] - S[0]] = true;

    for (i = 0; i < S.length; i  ) {
        for (j = 0; j < i; j  ) {
            var PossibleAKs = getAKs(S[i] - S[j]);
            for (k = 0; k < PossibleAKs.length; k  ) {
                var A = PossibleAKs[k][0];
                var K = PossibleAKs[k][17];

                var mustExistToBeBetter;
                if (K==1) {
                    mustExistToBeBetter = S[j]   A * bestSolution.length;
                } else {
                    mustExistToBeBetter = S[j]   A * K * (Math.pow(K,bestSolution.length) - 1)/(K-1);
                }

                if ((H[S[j]   A * K - S[0]]) && (H[mustExistToBeBetter - S[0]])) {
                    var possibleSolution=[S[j],S[j]   A * K,S[i]];
                    exp = K * K * K;
                    var NextVal = S[i]   A * exp;
                    while (H[NextVal - S[0]] === true) {
                        possibleSolution.push(NextVal);
                        exp = exp * K;
                        NextVal = NextVal   A * exp;
                    }

                    if (possibleSolution.length > bestSolution.length) {
                        bestSolution = possibleSolution;
                    }
                }
            }
        }
    }
    return bestSolution;
}

//var A= [ 1, 2, 3,5,7, 15, 27, 30,31, 81];
var A=[];
for (i=1;i<=3000;i  ) {
    A.push(i);
}
var sol=getBestGeometricSequence(A);

$("#result").html(JSON.stringify(sol));

Kodu burada kontrol edebilirsiniz: http://jsfiddle.net/6yHyR/1/

M N. göre çok büyük olduğunda, hala daha iyi olduğunu düşünüyorum, çünkü başka bir çözüm buldum korumak

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • CZTUTORIALS

    CZTUTORIALS

    28 Ocak 2011
  • jesiel santos

    jesiel santo

    15 Ocak 2009
  • UCBerkeley

    UCBerkeley

    3 Mayıs 2006