算法题值秋叶集问题(动态规划实现)
题目描述
小扣出去秋游,途中收集了一些红叶和黄叶,他利用这些叶子初步整理了一份秋叶收藏集 leaves, 字符串 leaves 仅包含小写字符 r 和 y, 其中字符 r 表示一片红叶,字符 y 表示一片黄叶。
出于美观整齐的考虑,小扣想要将收藏集中树叶的排列调整成「红、黄、红」三部分。每部分树叶数量可以不相等,但均需大于等于 1。每次调整操作,小扣可以将一片红叶替换成黄叶或者将一片黄叶替换成红叶。请问小扣最少需要多少次调整操作才能将秋叶收藏集调整完毕。
示例 1:
输入:leaves = “rrryyyrryyyrr”
输出:2
解释:调整两次,将中间的两片红叶替换成黄叶,得到 “rrryyyyyyyyrr”
示例 2:
输入:leaves = “ryr”
输出:0
解释:已符合要求,不需要额外操作
提示:
3 <= leaves.length <= 10^5
leaves 中只包含字符 ‘r’ 和字符 ‘y’
思路分析
动态规划解决秋叶集问题:
首先我们需要找到动态规划的条件和公式规则
这里题设要求我们最少需要多少次调整操作才能将秋叶收藏集调整完毕,我们可以将秋叶变成红黄红的秋叶集分成三个步骤:红,红黄,红黄红
首先我们将开始的秋叶集String字符串转换成字节数组arr
接着创建动态规划数组dp[][] = new int[3][arr.length];
分步骤分别获取得到全部红,全部为红黄,全部为红黄红的最少调整次数
其中:
(1)dp[0][i]:表示第i个秋叶全为红叶的最低调整次数,即若arr[i]为’y’,则dp[0][i] = dp[0][i - 1] + 1;
(2)dp[1][i]:表示第i个秋叶使得满足为红黄,调整的最少次数=将其当前状态之前全部变成红色的最少次数,加上调整当前为黄色的调整次数之和与上一个本身状态变成红黄的最少次数,加上将当前调整为黄色的最少次数之和的最小值
dp[1][i] = minNum(dp[0][i - 1] + (leavesArr[i] == ‘y’ ? 0 : 1),dp[1][i - 1] + (leavesArr[i] == ‘y’ ? 0 : 1));
(3)dp[2][i]:表示第i个秋叶使得满足红黄红, 调整的最少次数 = 将当前状态调整为红黄色,然后加上调整当前为红色的调整次数之和与上一本身状态变成红黄色的最少次数,加上将当前调整为红色的调整次数之和,两者的最小值
dp[2][i] = minNum(dp[1][i - 1] + (leavesArr[i] == ‘r’ ? 0 : 1),dp[2][i - 1] + (leavesArr[i] == ‘r’ ? 0 : 1));
最终dp[2][leavesArr.length - 1]即为将当前所有红叶和黄叶333调整为红黄红秋叶集的最少次数
代码实现
package com.bingym.algorithm.dynamicprogramming.autumnleaves;
import com.bingym.algorithm.dynamicprogramming.predictWinner.Solution;
public class AutumnLeavesCollection {
/*
*
秋叶集的收集问题:
小扣出去秋游,途中收集了一些红叶和黄叶,他利用这些叶子初步整理了一份秋叶收藏集 leaves, 字符串 leaves 仅包含小写字符 r 和 y, 其中字符 r 表示一片红叶,字符 y 表示一片黄叶。
出于美观整齐的考虑,小扣想要将收藏集中树叶的排列调整成「红、黄、红」三部分。每部分树叶数量可以不相等,但均需大于等于 1。每次调整操作,小扣可以将一片红叶替换成黄叶或者将一片
黄叶替换成红叶。请问小扣最少需要多少次调整操作才能将秋叶收藏集调整完毕。
示例 1:
输入:leaves = "rrryyyrryyyrr"
输出:2
解释:调整两次,将中间的两片红叶替换成黄叶,得到 "rrryyyyyyyyrr"
示例 2:
输入:leaves = "ryr"
输出:0
解释:已符合要求,不需要额外操作
提示:
3 <= leaves.length <= 10^5
leaves 中只包含字符 'r' 和字符 'y'
* */
public static void main(String[] args) {
String leaves = "rrryyyrryyyrr";
AutumnLeavesCollection solution = new AutumnLeavesCollection();
int operations = solution.minimumOperations(leaves);
System.out.println("将当前秋叶" + leaves + "调整为秋叶集的最少次数为:" + operations);
}
//利用动态规划求解其问题
public int minimumOperations(String leaves) {
char[] leavesArr = leaves.toCharArray();
int[][] dp = new int[3][leavesArr.length];
for (int i = 0; i < leavesArr.length; i++) {
//将所有的秋叶设置为红色,进行调整的最少次数
if (i == 0) {
if (leavesArr[i] == 'r') {
dp[0][i] = 0;
}else {
dp[0][i] = 1;
}
}else {//当i大于0,即存在两个即以上秋叶的时候
dp[0][i] = dp[0][i - 1] + (leavesArr[i] == 'r' ? 0 : 1);
}
//再将所有的秋叶设置为红黄色,进行调整的最少次数
//公式为:调整的最少次数=将其当前状态之前全部变成红色的最少次数,加上调整当前为黄色的调整次数之和
// 与上一个本身状态变成红黄的最少次数,加上将当前调整为黄色的最少次数之和的最小值
if (i == 0) {
dp[1][i] = dp[0][i];//因为第一个必须为红色,才能达到红黄的目的
}else {
dp[1][i] = minNum(dp[0][i - 1] + (leavesArr[i] == 'y' ? 0 : 1),dp[1][i - 1] + (leavesArr[i] == 'y' ? 0 : 1));
}
//最后将所有的秋叶设置为红黄红则,进行调整的最少次数
//此时由于上面已经设置成为红黄色,则:
//调整的最少次数 = 将当前状态调整为红黄色,然后加上调整当前为红色的调整次数之和
//与上一本身状态变成红黄色的最少次数,加上将当前调整为红色的调整次数之和,两者的最小值
if (i == 0 || i == 1) {
dp[2][i] = dp[1][i];//前两个必须红黄色
}else {
dp[2][i] = minNum(dp[1][i - 1] + (leavesArr[i] == 'r' ? 0 : 1),dp[2][i - 1] + (leavesArr[i] == 'r' ? 0 : 1));
}
}
//for循环结束,则dp[2][leavesArr.length - 1]即为将当前所有红叶和黄叶333调整为红黄红秋叶集的最少次数
return dp[2][leavesArr.length - 1];
}
private int minNum(int i, int j) {
return i < j ? i : j;
}
}