找回密码
 立即注册
查看: 65|回复: 0

牛客14487题解析:动态规划解决最小字符串翻转问题(附代...

[复制链接]
  • 打卡等级:即来则安
  • 打卡总天数:16
  • 打卡月天数:7
  • 打卡总奖励:111
  • 最近打卡:2025-07-12 15:59:47

21

主题

1

回帖

2469

积分

VIP会员

积分
2469
发表于 2025-6-19 16:02:03 | 显示全部楼层 |阅读模式


一、题目解读
牛客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] 并取最小值。
四、代码与注释
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespace std;

  5. int minFlips(string s) {
  6. int n = s.size();
  7. // dp[i][0]表示第i个字符为R时的最小操作次数
  8. // dp[i][1]表示第i个字符为G时的最小操作次数
  9. vector<vector<int>> dp(n, vector<int>(2, 0));

  10. // 初始化**个字符
  11. dp[0][0] = (s[0]!= 'R'); // 如果是G需要翻转
  12. dp[0][1] = (s[0]!= 'G'); // 如果是R需要翻转

  13. for (int i = 1; i < n; ++i) {
  14. // 当前字符为R时,前一个字符只能是R
  15. dp[i][0] = dp[i-1][1] + (s[i]!= 'R');
  16. // 当前字符为G时,前一个字符可以是R或G
  17. dp[i][1] = min(dp[i-1][0], dp[i-1][1]) + (s[i]!= 'G');
  18. }

  19. // 最终结果取**一位是R或G的最小值
  20. return min(dp[n-1][0], dp[n-1][1]);
  21. }

  22. int main() {
  23. string s;
  24. cin >> s;
  25. cout << minFlips(s) << endl;
  26. return 0;
  27. }
复制代码


注释说明:
● 使用动态规划避免重复计算,通过状态转移方程优化时间复杂度。
● 边界处理确保首字符符合初始状态要求。
● 循环中利用前缀状态信息更新当前状态,保证**性。

原文:动态规划

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表