Skip to content
This repository was archived by the owner on Jul 18, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
* [What's the difference between space and time complexity?](#q100)
* [What's an easy way to swap two values?](#q200)


## Questions

<a name="q100"></a>
### What's the difference between space and time complexity?

### What's the difference between space and time complexity

Space complexity refers to how memory usage increaes as the size of input increases. Time complexity refers to how the number of operations an algorithm requires to finish increases as the size of input increases.

Expand All @@ -20,7 +20,8 @@ Many solutions will involve trade-offs between space & time complexity - the low
------------------------------------------------------------------------

<a name="q200"></a>
### What's an easy way to swap two values?

### What's an easy way to swap two values

```python
# With a temp variable...
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Each directory contains a separate problem that you'll be tasked with solving.
Inside each directory, you'll find instructions for that problem, along with a
test file as well as an empty skeleton file.
test file as well as an empty skeleton file.

There isn't an official prescribed order for tackling the problems, though a
subjective ranking of the given problems from easiest to hardest might go
Expand All @@ -17,7 +17,7 @@ something like this:

For each problem, `cd` into the directory, read the instructions for the
problem, implement your solution in the skeleton file, then test it using the
provided test file.
provided test file.

The later problems definitely get progressively more difficult, especially when
it comes to deriving a more performant solution. Don't feel bad if you aren't
Expand All @@ -34,4 +34,4 @@ When you're confronted with a problem you haven't encountered before, the
general strategy (adapted from [George Pólya's Problem Solving
Principles](https://en.wikipedia.org/wiki/How_to_Solve_It)) is as follows:

https://github.com/LambdaSchool/CS-Wiki/wiki/Lambda-Problem-Solving-Framework
<https://github.com/LambdaSchool/CS-Wiki/wiki/Lambda-Problem-Solving-Framework>
18 changes: 9 additions & 9 deletions eating_cookies/README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
# Eating Cookies

Cookie Monster can eat either 0, 1, 2, or 3 cookies at a time. If he were given a jar of cookies with `n` cookies inside of it, how many ways could he eat all `n` cookies in the cookie jar? Implement a function `eating_cookies` that counts the number of possible ways Cookie Monster can eat all of the cookies in the jar.
Cookie Monster can eat either 0, 1, 2, or 3 cookies at a time. If he were given a jar of cookies with `n` cookies inside of it, how many ways could he eat all `n` cookies in the cookie jar? Implement a function `eating_cookies` that counts the number of possible ways Cookie Monster can eat all of the cookies in the jar.

For example, for a jar of cookies with `n = 3` (the jar has 3 cookies inside it), there are 4 possible ways for Cookie Monster to eat all the cookies inside it:

1. He can eat 1 cookie at a time 3 times
2. He can eat 1 cookie, then 2 cookies
2. He can eat 1 cookie, then 2 cookies
3. He can eat 2 cookies, then 1 cookie
4. He can eat 3 cookies all at once.
4. He can eat 3 cookies all at once.

Thus, `eating_cookies(3)` should return an answer of 4.

## Testing

For this problem, there's a test that tests your implementation with small inputs (n <= 10). There's also a separate test that tests your implementation with large inputs (n >= 50).
For this problem, there's a test that tests your implementation with small inputs (n <= 10). There's also a separate test that tests your implementation with large inputs (n >= 50).

You'll find that without implementing performance optimizations into your solution, your solution will likely hang on the large input test.
You'll find that without implementing performance optimizations into your solution, your solution will likely hang on the large input test.

To run the tests separately, run `python test_eating_cookies.py -k small` in order to run just the small input test. Run `python test_eating_cookies.py -k large` to execute just the large input test. If you want to run both tests, just run `python test_eating_cookies.py`.

You can also test your implementation manually by executing `python eating_cookies.py [n]`.

## Hints

* Since this question is asking you to generate a bunch of possible permutations, you'll probably want to use recursion for this.
* Think about base cases that we would want our recursive function to stop recursing on. How many ways are there to eat 0 cookies? What about a negative number of cookies?
* Once we've established some base cases, how can we recursively call our function such that we move towards one or more of these base cases?
* As far as performance optimizations go, caching/memoization might be one avenue we could go down? How should we make a cache available to our recursive function through multiple recursive calls?
* Since this question is asking you to generate a bunch of possible permutations, you'll probably want to use recursion for this.
* Think about base cases that we would want our recursive function to stop recursing on. How many ways are there to eat 0 cookies? What about a negative number of cookies?
* Once we've established some base cases, how can we recursively call our function such that we move towards one or more of these base cases?
* As far as performance optimizations go, caching/memoization might be one avenue we could go down? How should we make a cache available to our recursive function through multiple recursive calls?
20 changes: 13 additions & 7 deletions eating_cookies/eating_cookies.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
import sys

# The cache parameter is here for if you want to implement
# a solution that is more efficient than the naive
# a solution that is more efficient than the naive
# recursive solution
def eating_cookies(n, cache=None):
pass
pass


if __name__ == "__main__":
if len(sys.argv) > 1:
num_cookies = int(sys.argv[1])
print("There are {ways} ways for Cookie Monster to eat {n} cookies.".format(ways=eating_cookies(num_cookies), n=num_cookies))
else:
print('Usage: eating_cookies.py [num_cookies]')
if len(sys.argv) > 1:
num_cookies = int(sys.argv[1])
print(
"There are {ways} ways for Cookie Monster to eat {n} cookies.".format(
ways=eating_cookies(num_cookies), n=num_cookies
)
)
else:
print("Usage: eating_cookies.py [num_cookies]")

31 changes: 18 additions & 13 deletions eating_cookies/test_eating_cookies.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import unittest
from eating_cookies import eating_cookies

class Test(unittest.TestCase):

def test_eating_cookies_small_n(self):
self.assertEqual(eating_cookies(0), 1)
self.assertEqual(eating_cookies(1), 1)
self.assertEqual(eating_cookies(2), 2)
self.assertEqual(eating_cookies(5), 13)
self.assertEqual(eating_cookies(10), 274)
class Test(unittest.TestCase):
def test_eating_cookies_small_n(self):
self.assertEqual(eating_cookies(0), 1)
self.assertEqual(eating_cookies(1), 1)
self.assertEqual(eating_cookies(2), 2)
self.assertEqual(eating_cookies(5), 13)
self.assertEqual(eating_cookies(10), 274)

def test_eating_cookies_large_n(self):
self.assertEqual(eating_cookies(50, [0 for i in range(51)]), 10562230626642)
self.assertEqual(eating_cookies(100, [0 for i in range(101)]), 180396380815100901214157639)
self.assertEqual(eating_cookies(500, [0 for i in range(501)]), 1306186569702186634983475450062372018715120191391192207156664343051610913971927959744519676992404852130396504615663042713312314219527)
def test_eating_cookies_large_n(self):
self.assertEqual(eating_cookies(50, [0 for i in range(51)]), 10562230626642)
self.assertEqual(
eating_cookies(100, [0 for i in range(101)]), 180396380815100901214157639
)
self.assertEqual(
eating_cookies(500, [0 for i in range(501)]),
1306186569702186634983475450062372018715120191391192207156664343051610913971927959744519676992404852130396504615663042713312314219527,
)


if __name__ == '__main__':
unittest.main()
if __name__ == "__main__":
unittest.main()
6 changes: 4 additions & 2 deletions knapsack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,16 @@ Total value: 117
```

## Testing

For this problem, there are tests that test your implementation with small (10 items to consider), medium (200 items to consider), and large inputs (1000 items to consider).

You can run all of the tests with `python test_knapsack.py`, or run the tests individually with `python test_knapsack.py -k small`, `python test_knapsack.py -k medium`, or `python test_knapsack.py -k large`.

## Hints

1. Base cases you might want to consider for a naive recursive implementation of this problem are:
* What if there are no items left to consider?
* What if the item I'm considering is too large to fit in my bag's remaining capacity?
2. In order to move towards one of our base cases, we'll pick up an item from the pile to consider, and add it to a copy of our bag. Now we have two versions of our bag, one with the item we're considering, and one without. All we have to do now is pick the bag that yields us a higher value.
3. As far as caching for this problem is concerned, a simple hash table or array is not going to suffice, because each solution now depends upon two parameters: the number of items in our pile to consider, as well as the capacity of our bag. So we'll need a 2x2 matrix in order to cache our answers adequately.
2. In order to move towards one of our base cases, we'll pick up an item from the pile to consider, and add it to a copy of our bag. Now we have two versions of our bag, one with the item we're considering, and one without. All we have to do now is pick the bag that yields us a higher value.
3. As far as caching for this problem is concerned, a simple hash table or array is not going to suffice, because each solution now depends upon two parameters: the number of items in our pile to consider, as well as the capacity of our bag. So we'll need a 2x2 matrix in order to cache our answers adequately.
4. Here's another way we might consider tackling this problem: what if we iterated through every single element in our pile and assign each one a value given by its value/weight ratio. Then we can sort all of the items based on this assigned value such that those items with a higher value/weight ratio are at the top of our sorted list of items. From there, we can just grab off the items at the top of our list until our bag is full. What would be the runtime complexity of this scheme? Would it work in every single scenario for any pile of items?
40 changes: 21 additions & 19 deletions knapsack/knapsack.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,26 @@
import sys
from collections import namedtuple

Item = namedtuple('Item', ['index', 'size', 'value'])
Item = namedtuple("Item", ["index", "size", "value"])


def knapsack_solver(items, capacity):
pass


if __name__ == '__main__':
if len(sys.argv) > 1:
capacity = int(sys.argv[2])
file_location = sys.argv[1].strip()
file_contents = open(file_location, 'r')
items = []

for line in file_contents.readlines():
data = line.rstrip().split()
items.append(Item(int(data[0]), int(data[1]), int(data[2])))

file_contents.close()
print(knapsack_solver(items, capacity))
else:
print('Usage: knapsack.py [filename] [capacity]')
pass


if __name__ == "__main__":
if len(sys.argv) > 1:
capacity = int(sys.argv[2])
file_location = sys.argv[1].strip()
file_contents = open(file_location, "r")
items = []

for line in file_contents.readlines():
data = line.rstrip().split()
items.append(Item(int(data[0]), int(data[1]), int(data[2])))

file_contents.close()
print(knapsack_solver(items, capacity))
else:
print("Usage: knapsack.py [filename] [capacity]")

Loading