簡體   English   中英

如何優化此代碼? (也許使用LINQ?)

[英]How to optimize this code? (Maybe with LINQ?)

我有以下代碼:

ArrayList arrayA = new ArrayList();
ArrayList arrayB = new ArrayList();
ArrayList arrayC = new ArrayList();
ArrayList arrayD = new ArrayList();
ArrayList arrayE = new ArrayList();
ArrayList arrayF = new ArrayList();
ArrayList arrayG = new ArrayList();
ArrayList arrayH = new ArrayList();
ArrayList arrayI = new ArrayList();
ArrayList arrayJ = new ArrayList();

int n = 0;

for (decimal a = 0.1m; a <= 100m; a += 0.1m)
{
    for (decimal b = 100m - a; b > 0m; b -= 0.1m)
    {
        for (decimal c = 100m - b; c > 0m; c -= 0.1m)
        {
            for (decimal d = 100m - c; d > 0m; d -= 0.1m)
            {
                for (decimal e = 100m - d; e > 0m; e -= 0.1m)
                {
                    for (decimal f = 100m - e; f > 0m; f -= 0.1m)
                    {
                        for (decimal g = 100m - f; g > 0m; g -= 0.1m)
                        {
                            for (decimal h = 100m - g; h > 0m; h -= 0.1m)
                            {
                                for (decimal i = 100m - h; i > 0m; i -= 0.1m)
                                {
                                    for (decimal j = 100m - i; j > 0m; j -= 0.1m)
                                    {
                                        if ((a + b + c + d + e + f + g + h + i + j) == 100)
                                        {
                                            ++n;
                                            arrayA.Add(a);
                                            arrayB.Add(b);
                                            arrayC.Add(c);
                                            arrayD.Add(d);
                                            arrayE.Add(e);
                                            arrayF.Add(f);
                                            arrayG.Add(g);
                                            arrayH.Add(h);
                                            arrayI.Add(i);
                                            arrayJ.Add(j);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

任何想法如何優化呢? 這需要永遠執行。

基本上,所需的是知道0.1和100之間的10個數字的組合數目,而它們的總和恰好是100。(我需要知道組合數目和組合本身)

提前致謝

我不認為有一個直接解決此問題的方法,尤其是對於這類數字。 但是,這是一個非常籠統的想法,可以幫助您開發自己的算法:

  1. 了解有關Gosper的Hack的信息 它可以生成O(n)復雜度的組合。
  2. 您將認識到需要生成C(1000,10)組合,這不能直接用原始數據類型完成。 為了解決這個問題,您可以實現自己的類,該類可以通過必要的操作(例如加法和移位)來表示大位序列。(或者,您可以在標准庫中找到一個類似的類並進行擴展。)

我知道這不是一件容易的事,我也不想自己實現。 但這會給您O(n)的時間復雜性,您只需遍歷線性時間的組合,使用該位序列在步驟0.1中選擇介於0.1和100之間的數字,並檢查它們的總和是否為100。並添加位序列到最終的ArrayList。

在Ronan Thibaudau發出警告之后進行編輯:很抱歉,我直接跳入Java,但是我認為您可以在自己喜歡的語言/框架中找到相應的方法。

另一個修改:現在,該帖子與語言無關。 想法是完全一樣的。 如果您正在考慮使用大型組合的此類問題,則此想法可以為您提供O(n)的時間復雜度和O(n)的內存需求。 實際上,這保證了它將在可行的時間內運行,在給定足夠大的n的情況下會消耗可行的內存量。

自我編輯:我仍然在考慮這個問題,必須進行更正。 (我保留了一些錯誤的算法分析)

Gosper's Hack肯定會給您O(n)時間復雜度來生成組合,這對於實現可接受的優化實現至關重要。 但是,由於必須創建自己的類來表示位序列,因此必須實現自己的移位器,加法器,ands和諸如此類的東西(即,您不能直接將硬件用於這些操作)。 為此,您將需要另一個n循環。 這可能會使您的算法復雜度為O(n 2

它絕對不如O(n)好,但仍應滿足您的執行時間要求。

如果您真的想優化建議的算法,那么我將從忽略不必要的循環開始,如果總和> = 100,則繼續下去是沒有意義的,例如:

for (decimal a = 0.1m; a <= 100m; a += 0.1m)
{
    for (decimal b = 100m - a; b > 0m; b -= 0.1m)
    {
        if (a + b >= 100m)
             continue;

             for (decimal c = 100m - b; c > 0m; c -= 0.1m)
             {
                 if (a + b + c >= 100m)
                     continue;
                 ...

無論如何,您將永遠無法存儲所有組合。 例如,如果只有三個數字,則輸出將包含1000 ^ 2個結果。 您可以任意選擇第一個數字(0.1 .. 100,因此您有1000個選擇),與第二個數字相同,例如,我選擇0.5和42-第三個數字我固定為57.5-因此為1000 * 1000 * 1好的結果。 現在將其擴展為10個數字。

我想出了這是使用LINQ做到這一點的最佳方法:

var n = 1000;
var query =
    from a in Enumerable.Range(1, n)
    from b in Enumerable.Range(1, n - a)
    from c in Enumerable.Range(1, n - a - b)
    from d in Enumerable.Range(1, n - a - b - c)
    from e in Enumerable.Range(1, n - a - b - c - d)
    from f in Enumerable.Range(1, n - a - b - c - d - e)
    from g in Enumerable.Range(1, n - a - b - c - d - e - f)
    from h in Enumerable.Range(1, n - a - b - c - d - e - f - g)
    from i in Enumerable.Range(1, n - a - b - c - d - e - f - g - h)
    let j = n - a - b - c - d - e - f - g - h - i
    where j >= 1
    select new { a, b, c, d, e, f, g, h, i, j };

我選擇使用int並將數字乘以10而不是使用帶有0.1增量的decimal

現在,用1,000運行此命令似乎要花費很多時間。

所以我開始以較小的數字運行它,並得到以下結果:

10  1
11  10
12  55
13  220
14  715
15  2002
16  5005
17  11440
18  24310
19  48620
20  92378

那是n和返回的組合數。

事實證明,該級數是C(n - 1, n - 10) 因此,插入n = 1000可獲得2,634,095,604,619,700,000,000組合。

現在,在我的計算機上,如果我以n = 30運行,則需要11.551秒才能計算出10,015,005個組合。

如果對此進行數學計算,假設每年有365.25天,那么得出的數字將是需要花費96,271,110年才能計算n = 1000

甚至“ Deep Thought”在計算42時也更快。祝您好運。

這是一個答案(為簡單起見,從1到1000而不是0.1到100,只需將所有項目除以10即可得到0.1到100的值)

首先,我們將與生成器枚舉和惰性運算符一起使用,以避免出現內存問題,一切都會以1的可能性以流方式1流式傳輸到管道中,因此應在代碼運行時固定內存

var kitems = Enumerable.Range(1,1000);
var q = from a in kitems
        from b in kitems
        from c in kitems
        from d in kitems
        from e in kitems
        from f in kitems
        from g in kitems
        from h in kitems
        from i in kitems
        from j in kitems
        where a+b+c+d+e+f+g+h+i+j == 1000
        select new {a,b,c,d,e,f,g,h,i,j};
// Since everything is lazy evaluated, the 10 first results are near immediate (nothing past those is evaluate, this is good for testing, remove the take operator if you want the full dataset)
foreach(var item in q.Take(10))
{
    // Do whatever you want with the result here
}

讓我們對整數(1到1000,總和1000)進行推理。 令C(K,N)為涉及N個總數的K個變量的組合數。

對於單個變量,我們有1種可能性(a = 1000),即C(1,1000)= 1。 更一般地,C(1,N)= 1。

有兩個變量,我們有999個組合(a = 1,b = 999到a = 999,b = 1),我們看到C(2,1000)= C(1,999)+ C(1,998)+ C(1,997)+ ... C(1,1)。 更一般地,C(2,N)= N-1。

有了三個變量,我們得到a(= 1)的C(2,999),a = 2 ...的C(2,998)和a = 998的C(2,2)。 根據三角數的公式,C(3,N)= N.(N-1)/ 2。

對於四個變量,我們有a(= 1)的C(3,999),a = 2 ...的C(3,998)和a = 997的C(3,3)。 通過四面體數的公式C(4,N)= N.(N-1)。(N-2)/ 6。

依此類推(這只是Pascal的三角形),直到:

C(10,N)= N.(N-1)。(N-2)。(N-3)。(N-4)。(N-4)。(N-6)。(N-7) 。(N-8)。(N-9)/ 9!

C(10,1000)= 2634095604619702128324000

沒有希望通過枚舉來計算這個天文數字!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM