题目链接:https://leetcode.com/problems/paint-fence/
There is a fence with n posts, each post can be painted with one of the k colors.
You have to paint all the posts such that no more than two adjacent fence posts have the same color.
Return the total number of ways you can paint the fence.
Note:
n and k are non-negative integers.
思路: 题意说的是不能有超过连续两个相同的颜色, 也就是说最多有两个相邻柱子染同样颜色.
这是一个双重dp的问题,对于第i个柱子染什么颜色我们要考虑是否和之前染一样的颜色
1. 如果和i-1染一样的颜色,那么第i-1个柱子就不能和第i-2染一样的颜色
2. 如果和第i-1染不一样的颜色,那么第i个柱子的染色方案数即为 sum(i-1) * (k-1)
也就是为了得到第i个柱子的染色方案,我们需要利用之前的两个状态,一个是i-1和i-2染一样颜色的方案数,另一个是i-1和i-2染不一样颜色的方案数,这样我们需要两个dp数组dp1, dp2分别记录对应的状态
然后考虑两个dp数组的递推公式:
dp1[i] = dp2[i-1],这个表示如果i和i-1染一样的色,那么染色方案为dp2[i-1]
dp2[i] = (dp1[i-1] + dp2[i-1]) * (k-1),表示i和i-1染不一样染色,对于第i-1的每一种染色方案,我们有k-1种颜色可选
初始状态为:
dp1[1] = 0
dp2[1] = k
JAVA 代码如下:
class Solution {
public int numWays(int n, int k) {
if(n == 0 || k == 0) return 0;
int[] dp1 = new int[n+1], dp2 = new int[n+1];
dp1[1] = 0;
dp2[1] = k;
for(int i = 2; i <= n; i++) {
dp1[i] = dp2[i-1];
dp2[i] = (dp1[i-1] + dp2[i-1]) * (k-1);
}
return dp1[n] + dp2[n];
}
}
有了上面的基础之后我们还可以考虑状态压缩:
C++代码
class Solution {
public:
int numWays(int n, int k) {
if(n==0 || k==0 || (k==1 && n>2)) return 0;
int same = 0, diff = k, total = k;
for(int i = 2; i <= n; i++)
{
same = diff, diff = (k-1)*total;
total = same + diff;
}
return total;
}
};
参考: https://leetcode.com/discuss/85147/complete-explanation-o-n-time-o-1-space
还有一个进阶的题目:https://leetcode.com/problems/number-of-music-playlists/
思路差不多