算法题目分享:小美的01串翻转 | dp

最近遇到一个算法题目,感觉挺有意思,分享一下。原题和参考题解放在最后的链接中了。

题目

题目描述
小美定义一个 01 串的权值为:每次操作选择一位取反,使得相邻字符都不相等的最小操作次数。
例如,"10001"的权值是 1,因为只需要修改一次:对第三个字符取反即可。
现在小美拿到了一个 01 串,她希望你求出所有非空连续子串的权值之和,你能帮帮她吗?
输入描述:
一个仅包含'0'和'1'的字符串,长度不超过 2000。
输出描述:
所有非空子串的权值和。
示例1
输入
10001

输出
8

说明
长度为 2 的子串中,有 2 个"00"的权值是 1。
长度为 3 的 3 个子串权值都是 1。
长度为 4 的 2 个子串权值都是 1。
长度为 5 的 1 个子串权值是 1。
总权值之和为 2+3+2+1=8

题解

本题有意思的地方在于:dp[i][x]表示以第i个字符结尾的情况,那么怎么标记/计算开始呢? 没错,就是暴力hh。暴力枚举每一个开始

#include <algorithm>
#include <bitset> //STL位集容器
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex> //复数类
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>     //STL双端队列容器
#include <exception> //异常处理类
#include <fstream>
#include <functional> //STL定义运算函数(代替运算符)
#include <limits>
#include <list> //STL线性列表容器
#include <map>  //STL 映射容器
#include <iomanip>
#include <ios>    //基本输入/输出支持
#include <iosfwd> //输入/输出系统使用的前置声明
#include <iostream>
#include <istream>   //基本输入流
#include <ostream>   //基本输出流
#include <queue>     //STL队列容器
#include <set>       //STL 集合容器
#include <sstream>   //基于字符串的流
#include <stack>     //STL堆栈容器    
#include <stdexcept> //标准异常类
#include <streambuf> //底层输入/输出支持
#include <string>    //字符串类
#include <utility>   //STL通用模板类
#include <vector>    //STL动态数组容器
#include <cwchar>
#include <cwctype>
#include <unordered_map>
#include <unordered_set>
#include <numeric>
#include <bits/stdc++.h>
using namespace std;
/**
 * 详细请参考大佬的思路:https://www.cnblogs.com/odd-ryj/p/17665212.html
 * 题目中dp[i][x]表示从开始考虑到第[i]个字符,那么因为题目中要考虑所有长度怎么办,不能只考虑从开头到某个字符
 * 没错,就是暴力枚举每个开头
 *
 */
int main()
{
    // ios::sync_with_stdio(false);
    string ss;
    cin >> ss;
    vector<vector<int>> dp(ss.size() + 1, vector<int>(2, 0)); // dp[i][0] 表示第i个字符不变,dp[i][1]表示第i个字符要发生改变
    int res = 0;
    for (int startIndex = 0; startIndex < ss.size(); ++startIndex)
    {
        dp[startIndex][0] = 0; // 每次都要清空,而且dp是从前往后推导的,所以dp数组是可以复用的
        dp[startIndex][1] = 1;
        int tmpRes = -1;
        for (int endIndex = startIndex + 1; endIndex < ss.size(); ++endIndex)
        {

            if (ss[endIndex] == ss[endIndex - 1])
            { // 结尾字符只需要跟前一个字符比较即可
                // 相同,必须改一个
                dp[endIndex][0] = dp[endIndex - 1][1];
                dp[endIndex][1] = dp[endIndex - 1][0] + 1 ;
            }
            else
            {
                // 当前和前一位不同,要么都改,要么都不该
                dp[endIndex][0] = dp[endIndex - 1][0];
                dp[endIndex][1] = dp[endIndex - 1][1] + 1;
            }
            tmpRes = min(dp[endIndex][0], dp[endIndex][1]);
            res += tmpRes;
        }
        
    }
    cout << res << endl;
    return 0;
}

https://ac.nowcoder.com/acm/contest/63869/C
题解:https://www.cnblogs.com/odd-ryj/p/17665212.html

posted @ 2023-09-07 14:56  思wu邪  阅读(168)  评论(0编辑  收藏  举报