次の3つのトリックを使用して、O(n)でそれを実行できると思います。
累積合計
sum(A [0:k])を格納する配列C[k]を事前計算します。
これは、時間O(n)でC [k] = C [k-1] +A[k]を介して再帰的に実行できます。この配列の利点は、C [b] -C [a-1]を介してsum(A [a:b])を計算できることです。
最高の中点
要素がソートされているため、絶対値の合計を最小化するための最良のiを簡単に計算できます。実際、最高のiは常に真ん中のエントリによって与えられます。リストの長さが偶数の場合、2つの中央要素間のiのすべての値は、常に最小の絶対値を示します。
たとえば、リスト10、10、12、14の場合、中心要素は10と12であるため、iの値が10から12の間であれば、合計が最小になります。
反復検索
これで、要素を1回スキャンして、最適な値を見つけることができます。
1. Init s=0,e=0
2. if the score for A[s:e] is less than B increase e by 1
3. else increase s by 1
4. if e<n return to step 2
スコアがB未満である、見られたesの最大値を追跡します。これがあなたの答えです。
このループは最大で2n回回ることができるため、O(n)になります。
A [s:e]のスコアは、合計| A [s:e] -A [(s + e)/2]|で与えられます。
m =(s + e)/2とします。
score = sum |A[s:e]-A[(s+e)/2]|
= sum |A[s:e]-A[m]|
= sum (A[m]-A[s:m]) + sum (A[m+1:e]-A[m])
= (m-s+1)*A[m]-sum(A[s:m]) + sum(A[m+1:e])-(e-m)*A[m]
事前に計算された配列C[k]を使用して、この式の合計を計算できます。
編集
エンドポイントが常にnでなければならない場合は、次の代替アルゴリズムを使用できます。
1. Init s=0,e=n
2. while the score for A[s:e] is greater than B, increase s by 1
Pythonコード
アルゴリズムのPython実装は次のとおりです。
def fast(A,B):
C=[]
t=0
for a in A:
t+=a
C.append(t)
def fastsum(s,e):
if s==0:
return C[e]
else:
return C[e]-C[s-1]
def fastscore(s,e):
m=(s+e)//2
return (m-s+1)*A[m]-fastsum(s,m)+fastsum(m+1,e)-(e-m)*A[m]
s=0
e=0
best=-1
while e<len(A):
if fastscore(s,e)<B:
best=max(best,e-s+1)
e+=1
elif s==e:
e+=1
else:
s+=1
return best
print fast([1,2,10,10,12,14],7)
# this returns 4, as the 4 elements 10,10,12,14 can be chosen