有 k 种颜色的涂料和一个包含 n 个栅栏柱的栅栏,每个栅栏柱可以用其中一种颜色进行上色。
你需要给所有栅栏柱上色,并且保证其中相邻的栅栏柱 最多连续两个 颜色相同。然后,返回所有有效涂色的方案数。
注意:
n 和 k 均为非负的整数。
示例:
输入: n = 3,k = 2
输出: 6
解析: 用 c1 表示颜色 1,c2 表示颜色 2,所有可能的涂色方案有:
柱 1 柱 2 柱 3
----- ----- ----- -----
1 c1 c1 c2
2 c1 c2 c1
3 c1 c2 c2
4 c2 c1 c1
5 c2 c1 c2
6 c2 c2 c1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/paint-fence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第一种思路:
问组合就上回溯。
用一个变量记录前一个栅栏的颜色有没有和前前栅栏的颜色相同。
注意最后的返回值必须是 dfs(1, False) * k,而不能是 dfs(0, False)。
这是因为对于下标为 0 的栅栏(第一个栅栏),涂色是没有限制的。它可以涂任意 k 种颜色。
我们只能给第二个栅栏开始的栅栏加上颜色的限制。
时间复杂度:O(N)
空间复杂度:O(N)
class Solution:
def numWays(self, n: int, k: int) -> int:
@cache
def dfs(i, same_with_prev):
nonlocal n, k
if i == n:
return 1
if same_with_prev:
return dfs(i + 1, False) * (k - 1)
else:
return dfs(i + 1, True) + dfs(i + 1, False) * (k - 1)
return dfs(1, False) * k
第二种思路:
回溯不行,就考虑一下能不能用动态规划来实现。用F(n)来代表涂完前n个栅栏的解。
先分类讨论一下:
1. 如果当前栅栏跟前一个栅栏涂一样的颜色,可能性有 F(n - 2) * ( k - 1), 这里(k - 1)的1 代表的是前前栅栏的颜色。
2. 如果当前栅栏跟前一个栅栏涂不一样的颜色,可能性有 F(n - 1) * (k - 1) , 这里(k - 1)的1 代表的是前一个栅栏的颜色。
所以 F(n) = (F(n - 2) + F(n - 1) )* (k - 1)
class Solution(object):
def numWays(self, n, k):
"""
:type n: int
:type k: int
:rtype: int
"""
dp = [0] * (n + 3)
dp[0], dp[1], dp[2] = 0, k, k * k
for i in range(3, n + 1):
dp[i] = dp[i - 1] * (k - 1) + dp[i - 2] * (k - 1)
return dp[n]