926. Flip String to Monotone Increasing
又是一题很有意思的题目。而且是自己想出来的:)
开始想了一些其他的方法,dp,但是不管用,后来就想可能不是通用解法,而是有自己的解法的。
思路是这样的:
题目的意思翻译过来,就是数组从前往后找到一个位置,该位置前面的1全变为0,该位置后面的0全变为1,找到一个位置使这样的变换最少。
但是我们需要每次一个位置都把它左右全部都扫描一遍找到需要的变换数吗?不需要,只需要两个数组,分别记录从左到右的1的数量,和从右到左0的数量就可以了。感觉和前缀和类似,不过每次的区间都是到最边上,所以不用减去一个什么。
class Solution {
public:
int minFlipsMonoIncr(string S) {
int sz = S.size();
if (sz == 0)
return 0;
vector<int> oneFromBeg(sz, 0), zeroFromEnd(sz, 0);
oneFromBeg[0] = (S[0] == '1' ? 1 : 0);
for (int i = 1; i < sz; ++i)
oneFromBeg[i] = oneFromBeg[i-1] + (S[i] == '1' ? 1 : 0);
zeroFromEnd[sz-1] = (S[sz-1] == '0' ? 1 : 0);
for (int i = sz-2; i >= 0; --i)
zeroFromEnd[i] = zeroFromEnd[i+1] + (S[i] == '0' ? 1 : 0);
int minRet = zeroFromEnd[0];
for (int i = 1; i < sz; ++i)
minRet = min(minRet, zeroFromEnd[i]+oneFromBeg[i-1]);
minRet = min(minRet, oneFromBeg[sz-1]);
return minRet;
}
};
之前碰到过类似的题目,就是一个子串去掉一个最大和为多少的题目。
不太确定自己之后再次遇到会不会还能够做出来。。。
啊。。。看了评论区发现dp是可以的,而且是更加简洁的方法,自闭了。。。看来之前没有好好想dp的方法。
dp是这样的:
dp[i]: s[0->i]的解
countOnes[i]: s[0->i]中i的个数
所以:
1.s[i] == ‘1’,dp[i] = dp[i-1]
2.s[i] == ‘0’,dp[i] = min(dp[i-1]+1, countOnes[i-1])
class Solution {
public:
int minFlipsMonoIncr(string S) {
int sz = S.size();
if (sz == 0)
return 0;
vector<int> dp(sz, 0), countOnes(sz, 0);
countOnes[0] = (S[0] == '0' ? 0 : 1);
for (int i = 1; i < sz; ++i) {
if (S[i] == '1')
dp[i] = dp[i-1];
else
dp[i] = min(dp[i-1]+1, countOnes[i-1]);
countOnes[i] = countOnes[i-1] + (S[i] == '0'? 0 : 1);
}
return dp.back();
}
};
观察到只用到前一个变量,所以可以节省内存:
class Solution {
public:
int minFlipsMonoIncr(string S) {
int sz = S.size();
int countOnes = 0, flipCounts = 0;
for (char c : S) {
if (c == '0')
flipCounts = min(flipCounts+1, countOnes);
else
++countOnes;
}
return flipCounts;
}
};
这才是这题最标准的解法。但是自己想出的解法还可以吧,也不要完全否定。。。