@@ -26,7 +26,48 @@ TODO: Duru- please explain your approach, including a code sample
2626
2727### Generate Fibonacci using a Memoized approach
2828
29- TODO: Titus- please explain your approach, including a code sample
29+ This implementation uses a concept we previously discussed in a class session: memoization.
30+ Memoization is a technique that stores previously computed values to avoid redundant
31+ calculations. Our implementation checks if ` n ` has already been computed, and if so,
32+ it retrieves the value from memo, which saves on computation time. It uses a recursive
33+ approach to calculate the fibonacci value, but importantly it stores the result in
34+ a dictionary ` memo ` to prevent recalculating the same values multiple times on future
35+ runs. This approach is particularly valuable for algorithms that exhibit overlapping
36+ problems, or frequent use of similar calculations. Without memoization, recursive calls
37+ can lead to exponential time complexity, making computations infeasible for large inputs.
38+ However, by using a memoized approach and storing/reusing results, we found that our program
39+ is more efficient as ` n ` increases.
40+
41+ Below I have included a section of this approach:
42+
43+ ``` python
44+ def fibonacci_generator (n : int , memo : Dict[int , int ]) -> int :
45+ """ Generates the Fibonacci sequence up to the nth term using memoization."""
46+ # initialize a dictionary to store previously computed numbers.
47+ if memo is None :
48+ memo = {}
49+ # if the number has already been calculated, use it
50+ if n in memo:
51+ return memo[n]
52+ # create the base case for handling 1 & 2 fibonacci numbers
53+ base_case = 2
54+ if n < base_case:
55+ return n
56+ # calculate the fibonacci for nth number
57+ memo[n] = fibonacci_generator(n - 1 , memo) + fibonacci_generator(
58+ n - 2 , memo
59+ )
60+ # return the appropriate fibonacci number
61+ return memo[n]
62+ ```
63+
64+ As you can see in the above code, this memoized approach takes in a possible dictionary,
65+ ` memo ` and stores already computed results in said dictionary. Then, when computing the
66+ fibonacci number, it first looks to see if it was already calculated, then if not, it performs
67+ a recursive approach to find the value. This approach, as mentioned before, allows for faster
68+ time complexity, especially as the number of runs increases and previously calculated results
69+ are already store. However, it is still important to understand and weight the trade-off of time
70+ complexity and memory usage when considering a memoized approach.
3071
3172### Generate Fibonacci using an Iterative approach
3273
@@ -146,7 +187,28 @@ This is a chart using the values in the `Averages` table above, for the Recursiv
146187
147188# Results
148189
149- TODO: Titus to complete
190+ Our results from running our Fibonacci sequence experiments, using iterative, recursive, and
191+ memoized approaches show clear performance differences, with respect to time. The iterative
192+ method consistently performed the fastest across all test cases, with an average runtime of
193+ ` 0.000017121 sec ` with our largest experiment input. This shows that even as the sequence size
194+ increased, the iterative approach maintained its efficiency, proving a worst case time complexity
195+ of $O(n)$. In contrast, the recursive approach showed exponential time complexity $O(2^n)$,
196+ as our execution times skyrocket as the sequence size grew. While manageable for small inputs,
197+ the recursive method is impractical for larger Fibonacci numbers, as seen in the drastic jump to
198+ execution times. Our results highlight the inefficiency of recursion, which can be attributed
199+ to redundant calculations and the cost associated with function call overhead.
200+
201+ The memoized approach, which optimizes recursion by storing previously computed values, improved
202+ performance over the recursive approach. While not as fast as the iterative approach, memoization
203+ reduced run time compared to recursion, with an average runtime of ` 0.000111318 sec ` with our largest
204+ experimental input. Interestingly, if you view the above image highlight the time complexity of each approach,
205+ you will notice as the values increase for the memoization, you begin to see a plateau, showing that an
206+ increase in previously calculated results starts to drastically effect the run time as our values increase.
207+ Overall, our results suggest that for computing Fibonacci numbers, the iterative method is the best choice for
208+ run time efficiency, while memoization provides a viable compromise when a recursive approach is necessary.
209+
210+ Importantly, our results are ran and averaged across a variety of operating systems, including Windows, and Mac,
211+ in order to provide the most inclusive and well-rounded analysis possible.
150212
151213# Next Steps
152214
@@ -165,4 +227,4 @@ These references were utilized during the creation of the experimental harness u
165227* < https://github.com/Allegheny-Computer-Science-202-S2025/computer-science-202-algorithm-engineering-project-2-krishatcher >
166228 * timing and output logic in this repo influenced by AEP 2
167229* < https://stackoverflow.com/questions/2819625/how-to-use-a-callable-as-the-setup-with-timeit-timer >
168- * successfully using the ` timeit ` library
230+ * successfully using the ` timeit ` library
0 commit comments