Thread: finding the largest ascending subsequence..

  1. #76
    Banned
    Join Date
    Oct 2008
    Posts
    1,535
    you are correct

  2. #77
    Registered User
    Join Date
    Dec 2008
    Posts
    5

    Thumbs up

    Quote Originally Posted by root4 View Post
    my attempt:
    Code:
    #include <stdio.h>
    int foo(int a[],int size,int i,int j) {
      // pre-condition: j>i
      if(j>=size) return 1;
      int r1=foo(a,size,j,j+1)+(a[j]>a[i]);
      int r2=foo(a,size,i,j+1);
      return (r1>r2?r1:r2);
    }
    int main() {
      int a[]={45,1,21,3,33,6,53,9,18};
      printf("%u\n",foo(a,sizeof(a)/sizeof(int),0,1)); // 5
      int b[]={-3,-2,-1,4,8,6,53,9,18};
      printf("%u\n",foo(b,sizeof(b)/sizeof(int),0,1)); // 7
      int c[]={1,2,3,4,5,6,7,8,9,10};
      printf("%u\n",foo(c,sizeof(c)/sizeof(int),0,1)); // 10
      return 0
    }
    man you are a genious!!

  3. #78
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Here's my 2c though IMO the one posted by root4 is the best - short and sweet.
    Code:
    #include <stdio.h>
    
    int mxstart(int a[],int i,int j,int o,int l,int c,int p,int v)
    {
        if (i <= (l-1)) {
            if (j >= i) {
                if (a[j] <= a[o]) {
                    if (a[j] >= a[i])
                        return mxstart(a,i,j-1,j,l,c+1,p,v);
                    else
                        return mxstart(a,i,j-1,j-1,l,c,p,v);
                } else
                    return mxstart(a,i,j-1,o,l,c,p,v);
            }
            if (c >= p)
                p = c;
            else
                c = p;
    
            return mxstart(a,i+1,l-1,l-1,l,0,p,v);
        }
        else {
            if (v < l)
                return mxstart(a,v+1,l-1,l-1,l,0,p,v+1);
            else
                return (c >= p ? c : p);
        }
    }
    
    int main()
    {
        int c;
        int a[]={45,1,21,3,33,6,53,9,18};
        int l = (sizeof a / sizeof a[0]);
    
        c = mxstart(a,0,l-1,l-1,l,0,0,0);
        printf("longest ascending subsequence is %d\n", c);
        return 0;
    }

  4. #79
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    The function posted by root4 certainly is short and sweet, but it doesn't seem to work for all cases.

    For example:

    Code:
    {3, 4, 1, 2} and {2, 4, 1, 3}
    Both have a longest increasing subsequence of length 2. However, foo() returns 3 for both of them. Hopefully this is just a simple off-by-one error.

    mxstart() has a problem with these cases:
    Code:
    {2, 4, 1, 3}: should be 2, mxstart() says 3
    {1, 3, 4, 2}: should be 3, mxstart() says 2
    and dwks' longest_ascending() returns all sorts of incorrect results, even for trivial cases:
    Code:
    The answer on the left is what longest_ascending() returned.
    In parentheses is the correct answer.
    {4, 3, 2, 1}: 2 (1)
    {4, 1, 3, 2}: 3 (2)
    {4, 2, 3, 1}: 3 (2)
    {3, 4, 2, 1}: 3 (2)
    {3, 4, 1, 2}: 3 (2)
    {2, 4, 1, 3}: 3 (2)
    {2, 4, 3, 1}: 3 (2)
    {1, 4, 3, 2}: 3 (2)
    {3, 1, 4, 2}: 3 (2)
    {3, 2, 4, 1}: 3 (2)
    {2, 3, 4, 1}: 4 (3)
    {1, 3, 4, 2}: 4 (3)
    {2, 1, 4, 3}: 3 (2)
    {1, 2, 4, 3}: 4 (3)
    These were tested against a non-recursive reference implementation (which I assumed to be correct), and manually verified the cases that didn't match. The reference implementation in C can be found here: http://www.algorithmist.com/index.ph..._Subsequence.c

    This is what I came up with (but that isn't really fair because I've discussed this problem in school before). Its similar to what root4 did.

    The longest ascending subsequence (LAS) of array A is either:
    1. A[0] + the LAS of the rest of the array
    2. The LAS of the rest of the array without A[0]

    HOWEVER, there is an additional constraint. If the LAS is A[0] + LAS(rest of array), then A[0] must be less than the smallest element in LAS(rest of array). Also I take advantage of the fact that LAS(A) == LAS(A) with the minimum element in the sequence greater than INT_MIN. Hopefully INT_MIN doesn't appear in the array!

    Code:
    int maximum(int a, int b)
    {
       return a > b ? a : b;
    }
    
    int las_greater_than(int x, int *a, int lo, int count)
    {
       if (lo >= count)
          return 0;
       
       int max = las_greater_than(x, a, lo + 1, count);
       
       if (a[lo] > x)
          max = maximum(max, las_greater_than(a[lo], a, lo+1, count) + 1);
       
       return max;
    }
    
    int las(int *a, int count)
    {
       return las_greater_than(INT_MIN, a, 0, count);
    }
    Once again though, if you think this is amazing or something, I DIDN'T INVENT THIS ALGORITHM. I learned it through discussions in a class I took.
    Last edited by arpsmack; 01-17-2009 at 06:01 PM.

  5. #80
    Registered User
    Join Date
    Jan 2009
    Posts
    10
    root4 !!!

    Code:
    #include <stdio.h>
    int foo(int a[],int size,int i,int j) {
      // pre-condition: j>i
      if(j>=size) return 1;
      int r1=foo(a,size,j,j+1)+(a[j]>a[i]);
      int r2=foo(a,size,i,j+1);
      return (r1>r2?r1:r2);
    }
    int main() {
      int a[]={45,1,21,3,33,6,53,9,18};
      printf("%u\n",foo(a,sizeof(a)/sizeof(int),0,1)); // 5
      int b[]={-3,-2,-1,4,8,6,53,9,18};
      printf("%u\n",foo(b,sizeof(b)/sizeof(int),0,1)); // 7
      int c[]={1,2,3,4,5,6,7,8,9,10};
      printf("%u\n",foo(c,sizeof(c)/sizeof(int),0,1)); // 10
      return 0
    }
    for this input -- 7 8 2 1 7 i get 3
    but i should get 2

  6. #81
    Registered User
    Join Date
    Apr 2008
    Posts
    396
    I said it was an attempt, nothing more
    While there is no formal proof, it doesn't have any value.

    here's the patch, the previous version was indeed wrong (merged two branches that should not), the new version is less simple but probably more correct:
    Code:
    int foo(int a[],int size,int new,int i,int j) {
      if(j>=size) return 0;
      int r1=a[j]>a[i]?foo(a,size,0,j,j+1)+1+new:0;
      int r2=new?foo(a,size,1,j,j+1):0;
      int r3=foo(a,size,new,i,j+1);
      return r1>r2?(r1>r3?r1:r3):(r2>r3?r2:r3); // max(r1,r2,r3);
    }
    int main() {
      int a[]={...};
      printf("%u\n",foo(a,sizeof(a)/sizeof(int),1,0,1));
      return 0;
    }
    arpsmack version is more attractive. (and seems proved).
    Last edited by root4; 01-18-2009 at 06:29 PM.

  7. #82
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Yeah, my bad. I meant
    Code:
    int longest = 0;
    where I put
    Code:
    int longest = 1;
    Sigh.

    [edit] I don't claim that my new solution is completely correct, but it does at least pass those tests it failed earlier. (Sorry for my hackish perl script...)
    Code:
    $ perl -ne '/.(\d), (\d), (\d), (\d)......(\d)/; $o = `./long0 $1 $2 $3 $4 | sed 's/[^0-9]//g'`; chomp $o; print "$o ($5)\n"' in
    1 (1)
    2 (2)
    2 (2)
    2 (2)
    2 (2)
    2 (2)
    2 (2)
    2 (2)
    2 (2)
    2 (2)
    3 (3)
    3 (3)
    2 (2)
    3 (3)
    [/edit]
    Last edited by dwks; 01-18-2009 at 09:57 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #83
    Banned
    Join Date
    Oct 2008
    Posts
    1,535
    thanks

  9. #84
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    root4:

    Your solution now gets the correct answer for every input except a strictly decreasing sequence. It seems like a very minor problem. For example:
    Code:
    {2, 1}: should be 1, foo() says 0
    {3, 2, 1} should be 1, foo() says 0
    etc...
    dwks:

    longest_ascending() now works for all inputs I throw at it . And what a minor fix that was!

  10. #85
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    The earlier one was indeed wrong and in the spirit of updating here's my latest.
    Code:
    #include <stdio.h>
    
    int mxstart(int a[],int i,int j,int o,int l,int c,int p,int v)
    {
        if (i <= (l-1)) {
            if (o >= i) {
                if (j >= i) {
                    if (a[i] <= a[o]) {
                        if ((a[j] <= a[v]) && (a[j] >= a[i]))
                            return mxstart(a,i,j-1,o,l,c+1,p,j);
                        else
                            return mxstart(a,i,j-1,o,l,c,p,v); 
                    } else
                        return mxstart(a,i,o-1,o-1,l,0,p,o-1);
                } else {
                    if (c >= p)
                        p = c;
                    else
                        c = p;
                    return (c >= (l-i) ? c : mxstart(a,i,o-1,o-1,l,0,p,o-1));
                }
            } else
                return mxstart(a,i+1,l-1,l-1,l,0,p,l-1);
        } else
            return (c >= p ? c : p);
    }
    
    int main()
    {
        int c;
        int a[]={45,1,21,3,33,6,53,9,18};
        int l = (sizeof a / sizeof a[0]);
    
        c = mxstart(a,0,l-1,l-1,l,0,0,l-1); 
        printf("longest ascending subsequence is %d\n", c);
    }

  11. #86
    Registered User
    Join Date
    Apr 2008
    Posts
    396
    Your solution now gets the correct answer for every input except a strictly decreasing sequence
    Good catch. Indeed the function returns 0 if there is not at least a pair of ascending numbers (i.e. a result of 2), changing the final result in something like max(r1,r2,r3,new?1:0) should do the trick but there surely a way to make it more elegant. I won't spend more time on it, several solutions were proposed or hints for solutions, there's enough to play for the OP or the ones interested...

  12. #87
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    Quote Originally Posted by itCbitC View Post
    The earlier one was indeed wrong and in the spirit of updating here's my latest.
    I hate to be the bearer of bad news, but try one of these inputs:
    Code:
    {1, 3, 4, 2, 5}: mxstart() says 3, should be 4
    {1, 3, 5, 4, 2, 6}: mxstart() says 3, should be 4
    {4, 1, 3, 5, 2, 6}: mxstart() says 3, should be 4
    {1, 3, 4, 5, 2, 6}: mxstart() says 4, should be 5
    {2, 1, 4, 5, 3, 6}: mxstart() says 3, should be 4
    {1, 2, 4, 5, 3, 6}: mxstart() says 4, should be 5
    etc...
    By the way, this is the code I'm using to check your solutions. Just fill in YOUR_FUNC() with the details of however your function works. Run the program on the commandline passing it a number (1 - 12) and it will check all permutations of an increasing sequence of that size.

    I.E. - ./a.out 3 will check {1, 2, 3}, {1, 3, 2}, {2, 1, 3}, etc... (in no particular order)
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int lcs( int* a, int N ) {
       int *best, *prev, i, j, max = 0;
       best = (int*) malloc ( sizeof( int ) * N );
       prev = (int*) malloc ( sizeof( int ) * N );
     
       for ( i = 0; i < N; i++ ) best[i] = 1, prev[i] = i;
     
       for ( i = 1; i < N; i++ )
          for ( j = 0; j < i; j++ )
             if ( a[i] > a[j] && best[i] < best[j] + 1 )
                best[i] = best[j] + 1, prev[i] = j;  // prev[] is for backtracking the subsequence
     
       for ( i = 0; i < N; i++ )
          if ( max < best[i] )
             max = best[i];
     
       free( best );
       free( prev );
     
       return max;
    }
    
    void swap(int *a, int *b)
    {
       int temp = *a;
       *a = *b;
       *b = temp;
    }
    
    void permute(int k, int *s, int count)
    {
       int j;
       for (j = 2; j <= count; j++)
       {
          k /= (j-1);
          swap(&s[k%j], &s[j-1]);
       }
    }
    
    void print_array(int *a, int size)
    {
       int i;
       
       printf("{%d", a[0]);
       for (i = 1; i < size; i++)
          printf(", %d", a[i]);
       printf("}");
    }
    
    int fact(int n)
    {
       int res = n;
       while (--n > 1)
          res *= n;
       return res;
    }
    
    int YOUR_FUNC(int *a, int count)
    {
       ...
    }
    
    int main(int argc, char **argv)
    {
       if (argc < 2) return 0;
       
       int count = atoi(argv[1]);
       
       if (count < 1 || count > 12) return 1;
    
       int size = count * sizeof(int);
       
       int *inorder = malloc(size);
       int *a = malloc(size);
       
       int n, result, reference;
       
       for (n = 0; n < count; n++)
          inorder[n] = n+1;
       
       for (n = 0; n < fact(count); n++)
       {
          memcpy(a, inorder, size);
          permute(n, a, count);
          
          result = YOUR_FUNC(a, count);
          reference = lcs(a, count);
          
          if (result != reference)
          {
             print_array(a, count);
             printf(": you said %d, should be %d\n", result, reference);
          }
       }
    
       printf("Done.\n");
       
       return 0;
    }
    If no errors are printed using inputs 1 - 6 or so, I'd say your answer is probably correct.

  13. #88
    Registered User gil_savir's Avatar
    Join Date
    Jan 2009
    Posts
    13

    Thumbs up Anyone knows a good debugger (also) for recursive functions?

    Thanks guys. That really helps understanding my mistake. I was working on the same exercise and got to a code similar to dwks' code. I had a small flaw, which was very difficult to trace.

    BTW, the inline code versions suggested here might be beautiful in its compactness. Yet these do not contribute anything for understanding them.

    debugging a recursive function with all its self calls is a damn difficult! If anyone can recommend a debugger which shows clearly calls tree with watch for each node in the tree, I'll appreciate it.

    Thanks

  14. #89
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by gil_savir View Post
    debugging a recursive function with all its self calls is a damn difficult! If anyone can recommend a debugger which shows clearly calls tree with watch for each node in the tree, I'll appreciate it.

    Thanks
    Yes, that's ANOTHER good reason to not use recursion. But Visual Studio and gdb, which I think are among the most used debuggers, will show your call-stack, including recursion.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #90
    Registered User gil_savir's Avatar
    Join Date
    Jan 2009
    Posts
    13
    Quote Originally Posted by matsp View Post
    ... will show your call-stack, including recursion.
    Mats
    Most debuggers (also the one on Eclipse) show call-STACK. However, I would like to see a call-TREE. In some recursive functions, the call-stack is not enough for understanding which call is the parent/child of which call on the stack.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 22
    Last Post: 05-29-2009, 05:44 PM
  2. Finding the 3 largest numbers of the five entered
    By Bkgrant in forum C Programming
    Replies: 11
    Last Post: 02-13-2009, 01:08 PM
  3. finding the largest number in a binary search
    By Emeighty in forum C++ Programming
    Replies: 20
    Last Post: 07-31-2008, 03:19 AM
  4. Find largest and second largest number (help)
    By Arkon in forum C++ Programming
    Replies: 6
    Last Post: 01-20-2006, 11:21 PM
  5. Finding largest element in array
    By Chaplin27 in forum C++ Programming
    Replies: 2
    Last Post: 04-12-2005, 09:18 PM