有 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第一种思路:
问组合就上回溯。
用一个变量记录前一个栅栏的颜色有没有和前前栅栏的颜色相同,再用一个变量记录前一个栅栏的颜色。
结果发现超时……
class Solution(object):
def numWays(self, n, k):
"""
:type n: int
:type k: int
:rtype: int
"""
# 问组合就回溯
# 需要记录 前一个栅栏有没有和前前栅栏颜色相同
# 如果相同了,那么当前栅栏就不可以和前一个栅栏颜色相同
# 否则,当前栅栏可以为任意颜色
if not n or not k:
return 0
if n == 2:
return k * k
self.res = []
def backtrack(state, pre_color, index, tmp):
if index >= n:
self.res.append(tmp[:])
return
if state:
for i in range(k):
if i == pre_color:
continue
backtrack(False, i, index + 1, tmp + [i])
else:
for i in range(k):
if i != pre_color:
backtrack(False, i, index + 1, tmp + [i])
else:
backtrack(True, i, index + 1, tmp + [i])
backtrack(False, None, 0, [])
return len(self.res)
第二种思路:
回溯不行,就考虑一下能不能用动态规划来实现。用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]