LeetCode 926. 将字符串翻转到单调递增
题目描述
如果一个由 ‘0’ 和 ‘1’ 组成的字符串,是以一些 ‘0’(可能没有 ‘0’)后面跟着一些 ‘1’(也可能没有 ‘1’)的形式组成的,那么该字符串是单调递增的。
我们给出一个由字符 ‘0’ 和 ‘1’ 组成的字符串 S,我们可以将任何 ‘0’ 翻转为 ‘1’ 或者将 ‘1’ 翻转为 ‘0’。
返回使 S 单调递增的最小翻转次数。
示例 1
输入:“00110”
输出:1
解释:我们翻转最后一位得到 00111.
示例 2:
输入:“010110”
输出:2
解释:我们翻转得到 011111,或者是 000111。
示例 3:
输入:“00011000”
输出:2
解释:我们翻转得到 00000000。
提示:
- 1 <= S.length <= 20000
- S 中只包含字符 ‘0’ 和 ‘1’
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/flip-string-to-monotone-increasing
题解1:前缀和
选定一个位置,将字符串S分解成两段(不包括当前选定的位置),要使字符串单调递增,只需要将前半段所有的‘1’翻转为‘0’,后半段所有的‘0’翻转为‘1’,当前选定位置是‘1’还是‘0’不影响结果。
class Solution {
public:
int minFlipsMonoIncr(string S) {
int size = S.size();
if (size == 0)
return 0;
int l = 0, r = 0;//l和r分别代表左边‘1’的个数和右边‘0’的个数
for (int i = 0; i < size; i++)
if (S[i] == '0')//记录右边‘0’的个数
r++;
int ans = INT_MAX;
for (int i = 0; i < size; i++) {
if (i!=0&&S[i-1] == '1') {
//记录左边‘1’的个数,当i等于0时不存在左边,此时计算的是将所有‘1’转化为‘0’
l++;
}
if (S[i] == '0')
r--;
ans = min(ans, l + r);
}
return ans;
}
};
题解2:动态规划
可以把问题转化为:给定一个已经经过dp[i-1]次翻转而有序的字符串,如果在它的末尾加一个字符,那么需要多少次翻转才能使新字符串有序:
- dp[i-1]+1次(将新字符‘0’变为‘1’)
- 前面‘1’的个数次(新字符为‘0’且不翻转,同时要求前面的‘1’全部翻转为‘0’)
- 前面‘1’的个数次+1(新字符为‘1’翻转为‘0’,同时要求前面的‘1’全部翻转为‘0’)
- dp[i-1]+0次(新字符为‘1’且不翻转)
dp[i]等于:1和2之间的最小值,或者3和4之间的最小值。
class Solution {
public:
int minFlipsMonoIncr(string S) {
if (S.size() == 0)
return 0;
vector<int> dp(S.size());
dp[0] = 0;
int count = 0;//记录'1'的个数
for (int i = 1; i < S.size(); i++) {
if (S[i - 1] == '1')
count++;
if (S[i] == '0')
dp[i] = min(dp[i - 1]+1, count);
else
dp[i] = min(count + 1, dp[i - 1]);
}
return dp[S. size() - 1];
}
};