算法题目分享:小美的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