hollow's blog

By hollow, 13 years ago, In English

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.

  • Vote: I like it
  • +10
  • Vote: I do not like it

| Write comment?
»
13 years ago, # |
Rev. 5   Vote: I like it +10 Vote: I do not like it

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 years ago, # ^ |
      Vote: I like it +3 Vote: I do not like it

    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.

    • »
      »
      »
      8 years ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      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 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

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

    • »
      »
      »
      12 years ago, # ^ |
      Rev. 3   Vote: I like it 0 Vote: I do not like it

      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 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

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

        • »
          »
          »
          »
          »
          12 years ago, # ^ |
          Rev. 3   Vote: I like it 0 Vote: I do not like it

          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

          • »
            »
            »
            »
            »
            »
            12 years ago, # ^ |
              Vote: I like it 0 Vote: I do not like it

            i guess writeAnswer(i++,j--); thingy would also work provided all elements in the array are unique.

            • »
              »
              »
              »
              »
              »
              »
              12 years ago, # ^ |
                Vote: I like it 0 Vote: I do not like it

              I don't think so, try it up and see why :)

              • »
                »
                »
                »
                »
                »
                »
                »
                12 years ago, # ^ |
                Rev. 2   Vote: I like it 0 Vote: I do not like it

                can you think of a test case where my idea fails. Because for almost all inputs that i have, its working fine !

                • »
                  »
                  »
                  »
                  »
                  »
                  »
                  »
                  »
                  12 years ago, # ^ |
                  Rev. 4   Vote: I like it 0 Vote: I do not like it
                  5 6
                  1 2 3 4 5
                  1 2 3 4 5
                  
                • »
                  »
                  »
                  »
                  »
                  »
                  »
                  »
                  »
                  12 years ago, # ^ |
                    Vote: I like it 0 Vote: I do not like it

                  well, it gave me as expected, it gave me two pairs : 1,5 2,4

                  hence passed !

                • »
                  »
                  »
                  »
                  »
                  »
                  »
                  »
                  »
                  12 years ago, # ^ |
                    Vote: I like it 0 Vote: I do not like it

                  correct output:

                  1 5
                  2 4
                  3 3
                  4 2
                  5 1
                  
  • »
    »
    12 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    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.

    • »
      »
      »
      12 years ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

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

      • »
        »
        »
        »
        12 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

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

        • »
          »
          »
          »
          »
          12 years ago, # ^ |
          Rev. 2   Vote: I like it 0 Vote: I do not like it

          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 years ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    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 years ago, # ^ |
        Vote: I like it +8 Vote: I do not like it

      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 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    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 years ago, # |
  Vote: I like it 0 Vote: I do not like it

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 years ago, # ^ |
      Vote: I like it +1 Vote: I do not like it

    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.