LCP 19. 秋叶收藏集
小扣出去秋游,途中收集了一些红叶和黄叶,他利用这些叶子初步整理了一份秋叶收藏集 leaves, 字符串 leaves 仅包含小写字符 r 和 y, 其中字符 r 表示一片红叶,字符 y 表示一片黄叶。
出于美观整齐的考虑,小扣想要将收藏集中树叶的排列调整成「红、黄、红」三部分。每部分树叶数量可以不相等,但均需大于等于 1。每次调整操作,小扣可以将一片红叶替换成黄叶或者将一片黄叶替换成红叶。请问小扣最少需要多少次调整操作才能将秋叶收藏集调整完毕。
Sample:
输入:leaves = “rrryyyrryyyrr”
输出:2
解释:调整两次,将中间的两片红叶替换成黄叶,得到 “rrryyyyyyyyrr”
思路:
动态规划:
使用 3 个 dp 数组记录状态
dp[0][i] 代表从头开始全部修改成红色(纯红)需要修改几次
dp[1][i] 代表从头开始是红色,然后现在是黄色(红黄),需要修改几次
dp[2][i] 代表从头开始是红色,然后变成黄色,又变成红色(红黄红),需要修改几次
根据 i 是红是黄,判断转移情况
dp[0][i] 就很简单,如果是黄的,就比之前加一
dp[1][i] 可以从上一个纯红状态变化过来,也可以从上一个本身状态变化过来
dp[2][i] 可以从上一个红黄状态变化过来,也可以从上一个本身状态变化过来
所以最后要求的答案即:dp[2].back()
作者:ikaruga
链接:https://leetcode-cn.com/problems/UlBDOe/solution/ulbdoe-by-ikaruga/
也就是用一个dp表来记录状态。0区域代表全程全红,1区域代表前面是红后面是黄,2区域代表红黄红。由于取最小,每次判定的时候取最小值(上一个状态的继承)。
class Solution {
public:
int minimumOperations(string leaves) {
vector<vector<int> > dp(3, vector<int>(leaves.size(), 0));
for (int i = 0; i < leaves.size(); i++)
{
if (i < 1)
dp[0][i] = (leaves[i] != 'r'); //在0区域内,如果第一个数不是r,则要有一次交换
else
dp[0][i] = dp[0][i - 1] + (leaves[i] != 'r'); //不是第一个数时,区域0内不是r,在上一次的基础上加一次交换
if (i < 1)
dp[1][i] = dp[0][i]; //从头开始是r现在是y,如果是第一个格子,直接继承纯红色的变化次数,
//虽然这个状态格子是没有意义上的。因为本格子情况不可能出现
else
dp[1][i] = min((dp[0][i - 1] + (leaves[i] != 'y')), (dp[1][i - 1] + (leaves[i] != 'y') ) );
//dp[1]的位置,既可以从全红状态变过来,也可以从红黄状态变来,去最小情况
if (i < 2)
dp[2][i] = dp[1][i]; //第一格第二格都是需要复制过来状态(因为题目规定012每个区域至少有一个元素)
else //从红黄状态变来,或者从红黄红状态变来
dp[2][i] = min((dp[1][i - 1] + (leaves[i] != 'r')), (dp[2][i - 1] + (leaves[i] != 'r')));
}
//需要返回的值就是dp[2][i] 即红黄红情况,并且遍历完了整个str
return dp[2][leaves.size() - 1];
}
};