1. 程式人生 > >LeetCode-926 flip-string-to-monotone-increasing 字串翻轉到單調遞增

LeetCode-926 flip-string-to-monotone-increasing 字串翻轉到單調遞增

題目連結

LeetCode 周賽 107場 B題

https://leetcode-cn.com/contest/weekly-contest-107/problems/flip-string-to-monotone-increasing/

題意

中文題,這個遞增允許不變,例如全0或者全1也是按照遞增處理。

題解

        智障了= =竟然拖很長時間才做出來。剛開始想使用暴力(絕壁TLE),想到了使用DFS,即從第一個字元開始,如果是0,那麼有翻轉或者不翻轉兩種可能,再往下搜尋時判定上一位是0還是1,如果是0那麼這一位可以翻轉可以不翻轉,如果是1,那麼這一位就只能翻轉。

        這樣DFS而不考慮剪枝的話是TLE的。後來想了一下,全0或者全1的情況排除,只剩下一種情況:以i點為軸,左邊全為0,右邊全為1。這樣在極限的情況下就是全0或者全1的情況。那麼可以這樣考慮:以i為軸,i左邊所有的數1翻轉為0,右邊的數0翻轉成1。這樣在程式碼上,可以先遍歷一次字串,統計0或者1的總數,第二次遍歷,建立一個數組,儲存該點左邊有幾個0或者1。第三次遍歷,根據上面獲得的變數利用數學推導(解一元方程而已)計算出來翻轉次數。這樣在O(n)的時間複雜度上解決該問題。

Java 程式碼

class Solution {
    public static int Min(int a,int b){
        return a > b ? b : a;
    }
    
    public int minFlipsMonoIncr(String S) {
        int len = S.length();
        int num0 = 0;
        int[] left0 = new int[len];
        for(int i = 0;i < len;i++){
            if(S.charAt(i) == '0'){
                num0++;
            }
        }
        if(S.charAt(0) == '0'){
            left0[0] = 1;
        }else{
            left0[0] = 0;
        }
        for(int i = 1;i < len;i++){
            left0[i] = left0[i-1];
            if(S.charAt(i) == '0'){
                left0[i]++;
            }
        }
        int ans = Min(num0,(len - num0));
        for(int i = 0;i < len;i++){
            int now = i+1+num0-2*left0[i];
            ans = Min(ans,now);
        }
        return ans;
    }
}