/*
Flip String to Monotone Increasing
https://leetcode.com/problems/flip-string-to-monotone-increasing/

A binary string is monotone increasing if it consists of some number of 0's (possibly none), followed by some number of 1's (also possibly none).

You are given a binary string s. You can flip s[i] changing it from 0 to 1 or from 1 to 0.

Return the minimum number of flips to make s monotone increasing.

Example 1:

Input: s = "00110"
Output: 1
Explanation: We flip the last digit to get 00111.
Example 2:

Input: s = "010110"
Output: 2
Explanation: We flip to get 011111, or alternatively 000111.
Example 3:

Input: s = "00011000"
Output: 2
Explanation: We flip to get 00000000.
 

Constraints:

1 <= s.length <= 105
s[i] is either '0' or '1'.

*/

// AC - 24 ms
class Solution {
public:
    int minFlipsMonoIncr(string s) {
        int zero = 0, lis = 0;
        for(auto x : s) {
            if(x == '0') zero++;
            else lis++;
            lis = max(lis, zero);
        }
        return s.size() - lis;
    }
};

// AC - 20 ms
class Solution2 {
public:
    int minFlipsMonoIncr(string s) {
        int one = 0, flip = 0;
        for(auto x : s) {
            (x == '1' ? one : flip)++;
            flip = min(flip, one);
        }
        return flip;
    }
};

// AC - 36 ms
class Solution3 {
public:
    int minFlipsMonoIncr(string s) {
        int n = s.size(), ans = INT_MAX;
        vector<int> f0(n + 1), f1(n + 1);
        for(int i = 1, j = n - 1; j >= 0; i++, j--) {
            f0[i] += f0[i - 1] + (s[i - 1] == '0' ? 0 : 1);
            f1[j] += f1[j + 1] + (s[j] == '1' ? 0 : 1);
        }
        for(int i = 0; i <= n; i++) {
            ans = min(ans, f0[i] + f1[i]);
        }
        return ans;
    }
};

// WA
// class Solution {
// public:
//     int minFlipsMonoIncr(string s) {
//         int n = s.size();
//         int first_one = 0;
//         for(int i = 0; i < n; i++) {
//             if(s[i] == '1') {
//                 first_one = i;
//                 break;
//             }
//         }
//         int last_zero = n - 1;
//         for(int i = n - 1; i > 0 ; i--) {
//             if(s[i] == '0') {
//                 last_zero = i;
//                 break;
//             }
//         }
//         int flip_one = 0;
//         for(int i = 0; i < last_zero; i++) {
//             if(s[i] == '1') {
//                 flip_one++;
//             }
//         }
//         int flip_zero = 0;
//         for(int i = n - 1; i > first_one; i--) {
//             if(s[i] == '0') {
//                 flip_zero++;
//             }
//         }
//         return min(flip_zero, flip_one);
//     }
// };