Here is a summary of the problem:
Problems/input-1.txt |
Problems/input-2.txt |
Problems/input-3.txt |
I have 100 more problems in Problems/??.txt. That's what tests.txt runs.
As always, the challenge is to spot the recursion. This is a pretty typical recursion for a DP problem: Call DP(i), where you know that all houses with numbers less then i are painted. Then, in DP(), you try all possible colors, and return the minimum.
It's a little more complex than that though. My recursive procedure was DP(index, target, prev), where:
Let's do example 2.
DP(0, 3, -1) makes two recursive calls: - Paint house 0 color 1: Cost = 1 plus DP(1, 2, 1). - Paint house 0 color 2: Cost = 10 plus DP(1, 2, 2). Let's walk through the recursions: DP(1, 2, 1) means house[0] is color 1. Since house 1 is painted with color 2, that means you have to start a new group with house 1 and you only make one recursive call. That is: DP(2, 1, 2). DP(2, 1, 2) means house[1] is color 2. Since house 2 is painted with color 1, that means you have to start a new group with house 2 and you only make one recursive call. That is: DP(3, 0, 1). DP(3, 0, 1) means house[2] is color 1. Since house 3 is painted with color 2, that means you have to start a new group with house 3, and that would set target to -1. That means it's impossible, so DP(3, 0, 1) returns -1. DP(2, 1, 2) returns -1 too. DP(1, 2, 1) returns -1 too. So now we're back in DP(0, 3, -1), which is now going to call DP(1, 2, 2). DP(1, 2, 2) means house[0] is color 2. Since house 1 is also color 2, you make the recursive call: DP(2, 2, 2). DP(2, 2, 2) means house[1] is color 2. House[2] is color 1, so we call DP(3, 1, 1). DP(3, 1, 1) means house[2] is color 1. House[3] is color 2, so we call DP(4, 0, 2); DP(4, 0, 2) means house[3] is color 1. House[4] is unpainted, so we can do two things: - Paint it 1: which would call DP(5, -1, 1). That call is illegal, so we don't do it. - Paint it 2: which calls DP(5, 0, 2), and adds 1 to the answer. DP(5, 0, 2) -- we're in the base case: return 0. So DP(4, 0, 2) returns 1. DP(3, 1, 1) returns 1. DP(2, 2, 2) returns 1. DP(1, 2, 2) returns 1. So now we're back in DP(0, 3, -1) and our answer is 10 plus DP(1, 2, 2), which is 11. |
Your memoization cache stores the three variables. I made my a vector of vector of vectors of ints, whose size is O(m * target * n). You can use that as the running time of the program, too.
The other pitfall is to only use the leetcode examples for testing. I know we all want to submit as quickly as possible, but you should test. Basically, your program is going to have a bunch of conditions, and you should concoct an example that tests every single one of those before you submit. I know it's no fun, but that's better than not testing and finding a bug in the condition that you didn't test. It happened to me.
You can of course make this faster by, for example, shrinking houses by condensing groups of consecutive painted houses. I didn't do that, BTW, but it would work. It can also shrink the size of your memoization cache.