The constraint is that no more than two consecutive posts can have the same color. For each post, we can either paint it a different color from the previous post, or paint it the same color (but only if the two previous posts are different).
This leads to a recurrence: totalWays(i) = (k - 1) * (totalWays(i - 1) + totalWays(i - 2)). The first term handles painting post i differently from post i - 1 (k - 1 choices). The second term handles painting post i the same as post i - 1, which requires post i - 1 to be different from post i - 2.
totalWays(i) to return the number of valid ways to paint posts 1 through i.totalWays(1) = k and totalWays(2) = k * k.i > 2, use the recurrence: totalWays(i) = (k - 1) * (totalWays(i - 1) + totalWays(i - 2)).totalWays(n).class Solution:
def numWays(self, n: int, k: int) -> int:
def total_ways(i):
if i == 1:
return k
if i == 2:
return k * k
# Check if we have already calculated totalWays(i)
if i in memo:
return memo[i]
# Use the recurrence relation to calculate total_ways(i)
memo[i] = (k - 1) * (total_ways(i - 1) + total_ways(i - 2))
return memo[i]
memo = {}
return total_ways(n)Where is the number of fence posts.
The same recurrence can be computed iteratively instead of recursively. We fill an array from the base cases up to n, which avoids recursion overhead and stack depth issues.
This approach is often more efficient in practice since it avoids function call overhead and naturally iterates through states in order.
n is 1, return k. If n is 2, return k * k.totalWays of size n + 1.totalWays[1] = k and totalWays[2] = k * k.i from 3 to n, compute totalWays[i] = (k - 1) * (totalWays[i - 1] + totalWays[i - 2]).totalWays[n].class Solution:
def numWays(self, n: int, k: int) -> int:
# Base cases for the problem to avoid index out of bound issues
if n == 1:
return k
if n == 2:
return k * k
total_ways = [0] * (n + 1)
total_ways[1] = k
total_ways[2] = k * k
for i in range(3, n + 1):
total_ways[i] = (k - 1) * (total_ways[i - 1] + total_ways[i - 2])
return total_ways[n]Where is the number of fence posts.
Since the recurrence only depends on the previous two values, we do not need to store the entire array. We can use two variables to track totalWays(i - 1) and totalWays(i - 2), updating them as we iterate.
This optimization reduces space complexity from O(n) to O(1).
n is 1, return k.twoPostsBack = k and onePostBack = k * k.i from 3 to n:curr = (k - 1) * (onePostBack + twoPostsBack).twoPostsBack = onePostBack, onePostBack = curr.onePostBack.class Solution:
def numWays(self, n: int, k: int) -> int:
if n == 1:
return k
two_posts_back = k
one_post_back = k * k
for i in range(3, n + 1):
curr = (k - 1) * (one_post_back + two_posts_back)
two_posts_back = one_post_back
one_post_back = curr
return one_post_backWhere is the number of fence posts.
The problem forbids more than two consecutive posts with the same color. Some solvers mistakenly interpret this as no two adjacent posts can share a color, which is too restrictive. Two adjacent posts can have the same color as long as there is not a third consecutive post with that same color.
When n equals 1, there are exactly k ways. When n equals 2, there are k*k ways since any combination is valid (no three consecutive posts exist yet). Forgetting to handle these base cases or computing them incorrectly leads to wrong answers and potential index-out-of-bounds errors.
The recurrence totalWays(i) = (k-1) * (totalWays(i-1) + totalWays(i-2)) accounts for two scenarios: painting differently from the previous post, or painting the same as the previous post (which requires the two before that to be different). Confusing the logic of when same-color painting is allowed leads to an incorrect formula.