0

I am trying to make from f_rec (recursive function) to f_iter (iterative function) but I can't. (My logic was to create a loop to calculate the results of f_rec(n-1).

int f_rec(int n)
{
 if(n>=3)
   return f_rec(n-1)+2*f_rec(n-2)+f_rec(n-3);
 else 
   return 1;
}

int f_iter(int n)
{
}

I also think that my time complexity for the f_rec is 3^n , please correct me if I'm wrong.

Thank you

7
  • C or C++? The answer can be very different. Commented Jan 5, 2015 at 23:28
  • int f_iter(int n){} where is the body? Commented Jan 5, 2015 at 23:29
  • 1
    @ZoffDino I have no idea how it will differ. I mean without any overengineering. Commented Jan 5, 2015 at 23:29
  • @ZoffDino I'm sorry I can't see the difference , I'll remove the C++ tag Commented Jan 5, 2015 at 23:29
  • 1
    @Oleg Write my function is not a question that is on topic on SO. You can show us what you tried and what specifically are you having trouble with. Commented Jan 5, 2015 at 23:31

5 Answers 5

1

There are two options:

1) Use the discrete math lessons and derive the formula. The complexity (well if @Sasha mentioned it) will be O(1) for both memory and algorithm. No loops, no recursion, just the formula.

At first you need to find the characteristic polynomial and calculate its roots. Let's asssume that our roots are r1, r2, r3, r4. Then the n'th element is F(n) = A * r1^n + B * r2^n + C * r3^n + D * r4^n, where A, B, C, D are some unknown coefficients. You can find these coefficients using your initial conditions (F(n) = 1 for n <= 3).

I can explain it on russian if you need.

2) Use additional variables to store intermediate values. Just like @6052 have answered (he has answered really fast :) ).

Sign up to request clarification or add additional context in comments.

6 Comments

I'm really confused about O(1) for the run time of algorithm , could you explain please ? I thought I can't get better than O(n)
It's a linear homogeneous recurrence relation with constant coefficients. Like Fibonacci sequence. So you can easily derive the formula.
If I recall correctly those roots to the characteristic polynomial are often real numbers (or worse yet, irrational or transcendental), not integers, so they can't be used to get exact answers.
@rcgldr Why doesn't? Double works great, its precision is enough to represent even F(INT_MAX). I have no idea how long will it be calculated with the iterative version.
It's not strictly speaking O(1) though since evaluating the power takes non-const time (multiplications) depending on n... I forgot what the actual relation is, but would think something along the lines of O(lg n). Nitpicking, I know.
|
1

You can always calculate the newest value from the last three. Just start calculating from the beginning and always save the last three:

int f_iter (int n) {
    int last3[3] = {1,1,1};  // The three initial values. Use std::array if C++

    for (int i = 3; i <= n; ++i) {
        int new_value = last3[0] + 2 * last3[1] + last3[2];
        last3[0] = last3[1];
        last3[1] = last3[2];
        last3[2] = new_value;
    }
    return last3[2];
}

This solution need O(1) memory and O(n) runtime. There might exist a formula that calculates this in O(1) (there most likely is), but I guess for the sake of demonstrating the iteration technique, this is the way to go.

Your solution has exponential runtime: Every additional level spawns three evaluations, so you end up with O(3^n) operations and stack-memory.

2 Comments

Vielen Dank ! Was I right regarding the n^3 for the recursive function ?
I have made an EDIT for that
0

The following is the idea

  int first=1,second=1,third=1; /* if n<=3 then the respective is the answer */
  for(i=4;i<=n;i++)
  {
     int next=first+2*second+third;
     first=second;
     second=third;
     third=next;
  }
  cout<<"The answer is "<<next<<endl;

Memory is O(1) and time is O(n).

EDIT Your recursive function is indeed exponential in time , to keep it linear you can make use of an array F[n], and use memoization. First initialize F[] as -1.

    int f_rec(int n)
    {
        if(n>=3)
        {
           if(F[n]!=-1)return F[n];

           F[n]=f_rec(n-1)+2*f_rec(n-2)+f_rec(n-3);
           return F[n];       
        }  

        else 
           return 1;

}

Comments

0

Just keep three variables and roll them over

  • start with a, b and c all equal to 1
  • at each step new_a is a + 2*b + c
  • roll over: new_c is b, new_b is a
  • repeat the required number of steps

Comments

0

A bit of an overkill, but this can be further optimized by letting the what the variables represent change in an unfolded loop, combined with (link) Duff's device to enter the loop:

int f_iter(int n){
int a=1, b=1, c=1;
    if(n < 3)
        return(1);
    switch(n%3){
        for( ; n > 2; n -= 3){
            case 2:
                b = c + 2*a + b;
            case 1:
                a = b + 2*c + a;
            case 0:
                c = a + 2*b + c;
        }
    }
    return c;
}

2 Comments

definitely interesting
@Oleg - Even for 64 bit unsigned integers, the max value for n is 59, so the loop could have been completely unfolded and used a switch case with 57 lines (57 cases, 59 down to 3). For 32 bit signed integers, the max value for n is 30 (28 lines in the unfolded loop). ... or the loop could have been partially unfolded to some multiple of 3, like 6, 9, 12, ... lines.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.