Блог пользователя hollow

Автор hollow, 13 лет назад, По-английски

In many problems i see the tag "two pointers". I assume its a technique. I dont have an idea on it can anybody give any type of reference. Thanks.

  • Проголосовать: нравится
  • +10
  • Проголосовать: не нравится

»
13 лет назад, # |
Rev. 5   Проголосовать: нравится +10 Проголосовать: не нравится

I will try to describe this method on example of a problem.
Given two arrays (A and B) sorted in ascending order, and an integer x. we need to find i and j, such that a[i] + b[j] is equal to X.
i and j our pointers, at first step i is points to the first element of a, and j points to the last element of b.

i = 0; j = b.size() - 1;

move first pointer one by one through the array a, and correct position of the second pointer if needed

while (i < a.size())
{
   while(a[i] + b[j] > X && j > 0) j--;
   if (a[i] + b[j] == X) writeAnswer(i, j);
   i++;
}

Also, there was the same question in Russian, maybe it can helps. link to google-translated version
http://mirror.codeforces.com/blog/entry/4136

  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится

    In addition to post of goo.gl_SsAhv:
    The feature of this method is that solutions are O(n) (n=b.size() using his terminology) despite of possibility of decreasing second pointer with O(n) while 1 iteration of outer cycle made. It's right because every pointer will change only O(n) times.

    • »
      »
      »
      7 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      amm... should it not be O(a.size()+b.size()) in worst case like if x=101 , a=1 2 5 7 8 100 , b= 1 2 3 4 47

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    and what if we have to find all the pairs that sums up to X ?

    • »
      »
      »
      12 лет назад, # ^ |
      Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

      the same approach works as well, just continue moving your pointers and count the number of pairs.

      actually the "writeAnswer" function in goo.gl_SsAhv code will be called for all such pairs

      • »
        »
        »
        »
        12 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        I guess in that case we need to do this : writeAnswer(i++,j--), right ?

        • »
          »
          »
          »
          »
          12 лет назад, # ^ |
          Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

          no. this code works fine:


          #include <iostream> using namespace std; int n,a[100001],b[100001]; void writeAnswer(int ii,int jj){ cout<<a[ii]<<" "<<b[jj]<<endl; } int X; int main(){ cin>>n>>X; for(int i=0;i<n;i++){ cin>>a[i]; } for(int i=0;i<n;i++){ cin>>b[i]; } int i=0,j=n-1; while (i < n) { while(a[i] + b[j] > X && j > 0) j--; if (a[i] + b[j] == X) writeAnswer(i, j); i++; } while(1); //pause }

          this code may not work when the array values is not unique, anyway the main point is to understand two pointers technique

  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    i came up with this problem : http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=515

    it reminded me of almost the same algorithm as used here except it needs perhaps more than two pointers.

    can you help me in figuring out how to approach above mentioned problem given in the link.

    • »
      »
      »
      11 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      it is just a bruteforce. There is total 2^12 subsets, try all.

      • »
        »
        »
        »
        11 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        is there any more efficient algorithm if input size is much larger than this complete search ?

        • »
          »
          »
          »
          »
          11 лет назад, # ^ |
          Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

          answer can be vey big, so there is no big difference. there is O(sum * n * n + total_size_of_answer) dfs like approach. vertex is a pair (sum, last_used_number). in this graph you have to find all paths between two vertices, but the anwser can be very big as it mentioned above.

  • »
    »
    9 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    Is there any condition for arrays 'a' and 'b', like all the elements will be unique or others? If not, then how your given code will give correct ans under the following condition:

    a.size() = 6;
    X = 6;
    a[] = {1, 2, 3, 4, 5, 6};
    b[] = {1, 2, 3, 5, 5, 6};
    

    @goo.gl_SsAhv

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится +8 Проголосовать: не нравится

      Why don't you try it for yourself?

      If you mean "why the possible answer i=0, j=3 is not displayed", well, be more specific next time, and it's because the original problem is to find any one pair of indices. What if the problem asks to find all such pairs?

      1. The maximum running time is O(mn) instead of O(m+n), e.g., when X=2 and all elements of a and b are equal to 1. So we can actually use the straightforward algorithm (for i, for j, check a[i]+b[j]) instead of the two pointers method.

      2. The above bound can be improved to O(s) where s is the number of pairs in the answer. You can still patch the algorithm (while equal, go up and down) to make it output all s pairs in O(s).

      3. If you need the number of pairs and not the pairs themselves, it can also be done in O(m+n) by maintaining highest and lowest possible values of j instead of a single variable.

  • »
    »
    6 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    And since X - a[ i ] is independent of the second pointer j, your two-pointers example can be rewritten as follows.

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int main()
    {
        int m, n, X; cin >> m >> n >> X; int a[ m + 1 ], b[ n + 1 ]; 
        
        for( int i = 1; i <= m; cin >> a[ i++ ] );
    
        for( int j = 1; j <= n; cin >> b[ j++ ] );
        
        for( int i = 1, j = n; i <= m; i++ )
        {
            int Y = X - a[ i ];
            
            while( j >= 1 and b[ j ] > Y )
                j--;
                
            if( j >= 1 and b[ j ] == Y )
                cout << i << ' ' << j << '\n';
        }
    }
    
»
6 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

If array elements are not distinct, the worst case is when all elements of both arrays are equal and the sum we are looking for is a[0] + b[0]. In this case all n2 pairs of indices form the needed summation, thus the best approach is an O(n2) brute force, so an O(n) solution will not work.

  • »
    »
    6 лет назад, # ^ |
      Проголосовать: нравится +1 Проголосовать: не нравится

    If you need the indices of all pairs, you may have O(n^2) results, so a O(n) is not possible, but if you need just how many index pairs there are, it's still solveable in O(n), just count how many there equal there are of a and b, and result is equalA*equalB.