2017-04-06 58 views
2

我想了解這兩個指針算法方法,所以我一直在讀this article這兩個指針算法

因此,這裏的問題。假設我們有一個N個元素的數組。我們希望找到該數組中元素的最大連續序列,其中總和小於或等於M.我們必須返回元素序列總和的值。

所以假設我們有一組元素[2,1,3,4,5],我們的M是12. 我們會返回12,因爲3,4和5總和爲12。從文章

  • 我們在陣列的前端引入兩個指針lr表示我們連續的子數組的startIndex和endIndex的,與他們兩個。
  • 現在我們開始擴大我們的右指針r提供sum[l,r] <= M有一次,我們在達到這樣一個階段,我們沒有任何選擇,但 移動左指針以及和開始下降的總和,直到 我們在到達情況我們可以再次擴展我們的右指針 。
  • 當我們到達這一點時,我們需要移動左邊的指針 ,我們不斷更新我們迄今爲止取得的最大總和。

這裏是C++代碼。

#include <bits/stdc++.h> 
#define lli long long 
#define MAX 1000005 

using namespace std; 

lli A[MAX]; 

int main() 
{ 
    int n; 
    lli sum = 0;  
    cin >> n; 

    for (int i = 0; i < n; i++) cin >> A[i]; 

    int l = 0, r = 0; 
    lli ans = 0; 

    while (l < n) { 
     while (r < n && sum + A[r] <= M) { 
      sum += A[r]; 
      r++; 
     } 
     ans = max(ans, sum); 
     sum -= A[l]; 
     l++; 
    } 

    cout << ans << endl; 
    return 0; 
} 

但我不明白爲什麼這種方法有效。我們沒有考慮所有可能的連續子序列。只要總和超過,我們就會記錄下我們當前的子序列長度,比較它是否大於前一個,然後簡單地增加l並重復該過程。

我不明白這是如何產生正確的結果。

+1

你忘記了不僅l遞增,而且前一個「L」個元素的值正在與總和相除。然後總和包含新'L'和'R'之間的所有剩餘元素,不需要重新計算該總和(用'R = L'重新開始循環)。我也認爲(沒有讀過這篇文章),有一個隱含的要求是> = 0,所以總和只能增長。 – antipattern

回答

3

該方法的工作原理是因爲對於每個r指針,當前l實際上表示最左邊的一個,使得總和仍低於閾值。

因此,沒有必要查看在r指針處結束的所有其他序列。

但是,如果允許負數,則該方法無效。在這種情況下,更長的序列不一定意味着總和會增加。

2

該算法起作用。它假定數組中的所有值都是正數(或0),因此對於固定的l,從1開始的最佳連續序列可以通過while循環找到,方法是添加正或零元素,直到當前總和達到前的最後一個r M.

那麼你知道從l開始並在r之前停止的序列小於當前序列,並且在r之後停止的序列太大(> M)。因此,您只需將當前總和與先前的最佳值進行比較,然後轉到l的下一個值。

如果整數可能是負數,那麼這是行不通的。