一、题目解读牛客14487题要求给定一个仅包含字符 'R' 和 'G' 的字符串,通过翻转操作(将字符 'R' 变为 'G' 或反之)使其满足:所有字符相同,且相邻字符不同。需要求出最小翻转次数。题目本质是寻找一种优化策略,在限制条件下实现状态转换的最小代价。 二、解题思路:动态规划1. 状态定义:使用二维DP数组 dp[j],其中 dp[0] 表示前 i 个字符全部为 'R' 的最小翻转次数,dp[1] 表示前 i 个字符全部为 'G' 的最小次数。 2. 边界条件:首字符需根据当前状态判断是否需要翻转(例如,若首字符为 'G' 但要求全 'R',则翻转一次)。 3. 状态转移: 若当前字符为 'R',前一个字符必须为 'G'(否则需翻转),因此 dp[0] = dp[i-1][1] + (s!= 'R'); 若当前字符为 'G',前一个字符可为 'R' 或 'G',取两者中较小值:dp[1] = min(dp[i-1][0], dp[i-1][1]) + (s!= 'G')。 4. 最终结果:取末尾字符为 'R' 或 'G' 的最小值,即 min(dp[n-1][0], dp[n-1][1])。 三、解题步骤1. 初始化:创建 dp[n][2] 数组,根据首字符状态计算初始值。 2. 循环处理每个字符: 根据当前字符与目标状态(全 'R' 或 'G')判断是否需要翻转,更新对应 dp 值。 利用前一个状态的最优解推导当前状态。 3. 返回最终结果:比较 dp[n-1][0] 和 dp[n-1][1] 并取最小值。 四、代码与注释
- #include <iostream>
- #include <vector>
- #include <algorithm>
- using namespace std;
- int minFlips(string s) {
- int n = s.size();
- // dp[i][0]表示第i个字符为R时的最小操作次数
- // dp[i][1]表示第i个字符为G时的最小操作次数
- vector<vector<int>> dp(n, vector<int>(2, 0));
-
- // 初始化第一个字符
- dp[0][0] = (s[0]!= 'R'); // 如果是G需要翻转
- dp[0][1] = (s[0]!= 'G'); // 如果是R需要翻转
-
- for (int i = 1; i < n; ++i) {
- // 当前字符为R时,前一个字符只能是R
- dp[i][0] = dp[i-1][1] + (s[i]!= 'R');
- // 当前字符为G时,前一个字符可以是R或G
- dp[i][1] = min(dp[i-1][0], dp[i-1][1]) + (s[i]!= 'G');
- }
-
- // 最终结果取最后一位是R或G的最小值
- return min(dp[n-1][0], dp[n-1][1]);
- }
- int main() {
- string s;
- cin >> s;
- cout << minFlips(s) << endl;
- return 0;
- }
复制代码
注释说明: ● 使用动态规划避免重复计算,通过状态转移方程优化时间复杂度。 ● 边界处理确保首字符符合初始状态要求。 ● 循环中利用前缀状态信息更新当前状态,保证最优性。
原文:牛客14487
|