剑指 Offer II 092. 翻转字符(926. 将字符串翻转到单调递增)

题目:

 

 

 

思路:

【1】动态规划的方式

【2】前缀和的方式

代码展示:

前缀和的方式:

//时间16 ms击败36.61%
//内存42.2 MB击败47.49%
//本身就是利用了:最终的字符串左边全 0 右边全1的特性
//(假设到了某个点,该点不反转,将左边的全部置为0,与右边全部置为1)
//(通过全部列举的到全部答案,然后从中找出翻转最少的)
//时间复杂度:O(n)
//空间复杂度:O(n)
//思路比较清晰的版本
class Solution {
    public int minFlipsMonoIncr(String s) {
        char[] c = s.toCharArray();
        int length = c.length;

        int[] left = new int[length];
        int[] right = new int[length];
        for (int i = 1; i < length; i++) {
            left[i] += left[i - 1];
            if (c[i - 1] == '1') left[i]++;
        }

        for (int i = length - 2; i >= 0; i--) {
            right[i] += right[i + 1];
            if (c[i + 1] == '0')  right[i]++;
        }
        
        int res = length;
        for (int i = 0; i < length; i++) {
            res = Math.min(left[i] + right[i], res);
        }
        return res;
    }
}

//优化的版本
//时间6 ms击败98.54%
//内存42.1 MB击败56.28%
class Solution {
    public int minFlipsMonoIncr(String s) {
        char[] cs = s.toCharArray();
        int n = cs.length, ans = n;
        int[] sum = new int[n + 10];
        for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + (cs[i - 1] - '0');
        for (int i = 1; i <= n; i++) {
            int l = sum[i - 1], r = (n - i) - (sum[n] - sum[i]);
            ans = Math.min(ans, l + r);
        }
        return ans;
    }
}

 

动态规划的方式:

//时间41 ms击败7.95%
//内存49.5 MB击败9.63%
//规范的动态规划写法
class Solution {
    //dp[i][0]表示前i个元素,最后一个元素为0的最小翻转次数;
    //dp[i][1]表示前i个元素,最后一个元素为1的最小翻转次数
    public int minFlipsMonoIncr(String s) {
        int dp[][]=new int[s.length()][2];
        // 初始化
        // 这里分明是列举了两种情况,dp[0][0]代表最后元素为0的情况,dp[0][1]代表最后元素为1的情况
        // 其次为什么是要记录两个呢?因为字符 0 前面的相邻字符一定是 0,字符 1 前面的相邻字符可以是 0 或 1。
        dp[0][0]=s.charAt(0)=='0'?0:1;
        dp[0][1]=s.charAt(0)=='1'?0:1;
        //状态转移
        for (int i = 1; i <s.length() ; i++) {
            dp[i][0]=dp[i-1][0]+(s.charAt(i)=='0'?0:1);
            dp[i][1]=Math.min(dp[i-1][0],dp[i-1][1])+(s.charAt(i)=='1'?0:1);
        }
        return Math.min(dp[s.length()-1][0],dp[s.length()-1][1]);
    }
}

//又由于使用动态规划的话,其实不一定需要保留那么多变量,所以存储的变量可以简化
//时间4 ms击败99.37%
//内存42 MB击败70.92%
//时间复杂度:O(n),其中 n 是字符串 s 的长度。需要遍历字符串一次,对于每个字符计算最小翻转次数的时间都是 O(1)。
//空间复杂度:O(1)。使用空间优化的方法,空间复杂度是 O(1)
class Solution {
    public int minFlipsMonoIncr(String s) {
        int dp0 = 0, dp1 = 0;
        for (char ch : s.toCharArray()) {
            //先更新dp[i][1],需要用到dp[i-1][0] 由于只有0和1,也不在使用三目运算
            dp1 = Math.min(dp0, dp1) + ('1' - ch);
            dp0 += ch - '0';
        }
        return Math.min(dp0, dp1);
    }
}
posted @ 2023-03-14 14:44  忧愁的chafry  阅读(26)  评论(0编辑  收藏  举报