2017-03-22 10 views
5

私は解決するためにリスト全体を(少なくともかなり確かめる)必要がある問題があります。問題は、そのリスト内の別の(より大きい)要素までを加算する、リスト内の連続する数字の最大数を把握することです。もし存在しなければ、リストの中で最も大きな値を候補集計とし、1を要素の最大連続数とする。リスト全体を通過する必要があるPythonコードの高速化

私の一般的なコードは機能しますが、大規模なリスト(> 500,000個の要素)ではそれほどうまく機能しません。私はちょうど私が問題に異なってアプローチする方法についてのヒントを探しています。私の現在のアプローチ:

L = [1,2,3,4,5,6,7,8,9,10] 
candidate_sum = L[-1] 
largest_count = 1 
N = len(L) 
i = 0 

while i < N - 1: 
    s = L[i] 
    j = 0 
    while s <= (N - L[i + j + 1]): 
     j += 1 
     s += L[i+j] 
     if s in L and (j+1) > largest_count: 
      largest_count = j+1 
      candidate_sum = s 
    i+=1 

この場合には、答えは次のようになり[1,2,3,4]、彼らは10まで追加し、長さが4であるように(明らかに、この例のLは、非常に単純な例です) 。

私はその後にループ条件ながら、初期を変更することで、より速くそれを作った:

while i < (N-1)/largest_count 

ない偉大な仮定が、数値の分布がやや均一であるので、後半に2つの数字という基本的な考え方リストは平均してリストの最後の数よりも大きいため、失格となります。

私はちょうど探しています:

  • 可能なボトルネック
+4

問題をより正確に定義する必要があります。リストは常にソートされ単調ですか?そこにはどんなギャップもありますか?最良の解決策は、正確な問題の記述に応じて異なります。 –

+1

@ŁukaszRogalskiリストは常にソートされています。すべての要素が一意であるため、リストは厳密に増加しています。連続する数字の間には空白があります。 – dimebucker91

答えて

4
  • をしようとする異なるアプローチについての

  • 提案は厳密に昇順ません:要素またはサブ配列のない重複を、可能な単一ソリューション

  • 任意の間隔:なしnum S上のメインループが並列化され

    #define TYPE int 
    
    int max_subsum(TYPE arr [], int size) { 
        int max_length = 1; 
    
        TYPE arr_fst = * arr; 
        TYPE* num_ptr = arr; 
    
        while (size --) { 
         TYPE num = * num_ptr++; 
    
         TYPE* lower = arr; 
         TYPE* upper = arr; 
    
         TYPE sum = arr_fst; 
         int length = 1; 
    
         for (;;) { 
         if (sum > num) { 
          sum -= * lower++; 
          -- length; 
         } 
         else if (sum < num) { 
          sum += * ++upper; 
          ++ length; 
         } 
         else { 
          if (length > max_length) { 
           max_length = length; 
          } 
    
          break; 
         } 
         } 
        } 
    
        return max_length; 
    } 
    

    :eticalショートカットは、ポインタ演算、数値型の上疑似多型を使用してブルートフォースを操作する

効率的なCの実装を有しています。 arrための動的配列リストタイプとfor eachループ使ってPython 3に比較的直接的な翻訳:

def max_subsum(arr): 
    max_len = 1 
    arr_fst = arr[0] 

    for n in arr: 
     lower = 0 
     upper = 0 

     sum = arr_fst 

     while True: 
     if sum > n: 
      sum -= arr[lower] 
      lower += 1 
     elif sum < n: 
      upper += 1 
      sum += arr[upper] 
     else: 
      sum_len = upper - lower + 1 

      if sum_len > max_len: 
       max_len = sum_len 

      break 

    return max_len 

このmax_subsumが部分関数です。 Pythonのリストは空にすることができます。このアルゴリズムは、高速の索引付けと静的型付き算術を提供するCのような命令型言語に適しています。どちらもPythonでは比較的高価です。よりパフォーマンス普遍的な定量化のためのsetデータ型を使用して、Pythonの動的型付け算術を避け、あなたにかなり類似した(完全に定義された)アルゴリズムは、より効率的に解釈することができます:私は可能性を無視するつもりだ

def max_subsum(arr): 
    size = len(arr) 
    max_len = 0 

    arr_set = set(arr) 

    for i in range(size): 
     sum = 0 
     sum_len = 0 

     for j in range(i, size): 
     sum_mem = sum + arr[j] 

     if num_mem not in arr_set: 
      break 

     sum = sum_mem 
     sum_len += 1 

     if sum_len > max_len: 
     max_len = sum_len 

    return max_len 
2

あなたはそれを理解することができますが、あなたの質問に答えるために「それを行うより速い方法はありますか?」はい:あなたのループの1つを削除するために累積合計といくつかの数学を使用しています。

import numpy as np 

L = np.random.randint(0,100,100) 
L.sort() 
cum_sum = np.cumsum(L) 

start = 0 
end = 0 

target = 200 

while 1: 
    total = cum_sum [end-1] - (cum_sum [start-1] if start else 0) 
    if total == target: 
     break 
    elif total < target: 
     end += 1 
    elif total > target: 
     start += 1 
    if end >= len(L): 
     raise ValueError('something informative') 
+0

解決できない場合はこのコードで処理できません。すべてのループの最後に、 'start <= end'と' end

+0

@LakshayGarg 'start'は、' L'がソートされていれば 'cum_sum'がソートされているので、' end'より大きくすることはできません。それらが等しい場合、 'end'は次の反復でインクリメントされます。 – Aaron

+0

@LakshayGarg実際には、すべての 'L'が> 0であり、' L'がソートされているわけではありませんが、私が与えた例では成り立ちます。このメソッドが機能するには(重要な変更を加えることなく)いくらか必要です。 – Aaron

関連する問題