题意理解

对于一个二进制字符串,我们只有一次机会选择其中一段连续的区间,将其中每个字符取反(即0变为1,1变为0),当然也可以不更新字符串。我们希望最后得到的字符串表示的数字最大。

方法一

暴力枚举
使用双重循环,列举出所有取反的可能性,并从中去最大值。由于是连续反转的,反转操作和确定反转的右边界可以公用一个循环。

具体代码如下:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param num string字符串 
     * @return string字符串
     */
    string maxLexicographical(string num) {
        // write code here
        string maxm = num;
        //遍历反转的起始位置
        for (int i=0;i<num.size();i++)
        {
            string ss = num;
            //遍历反转的长度
            for (int j=i;j<num.size();j++)
            {
                if (ss[j]=='1') ss[j] = '0';
                else ss[j] = '1';
                //判断大小
                if (ss > maxm) maxm = ss;
            }
        }
        return maxm;
    }
};

时间复杂度: O(N2)O(N^2)。使用了双重循环。
空间复杂度: O(N)O(N)。使用了两个字符串分别记录最大值和当前反转后的字符串。

方法二

注意到二进制字符串左侧为高位,右侧为低位。为了使数字更大,我们要把最左侧的第一个0改为1。除此之外,我们还注意到,最高位为1后面全为0,是大于最高位为0后面全为1的(例如100大于011),所以我们不会为了后面存在大量的0而改变当前位置上的1。

我们的过程为,从左往右遍历字符串,遇到第一个0时将其改为1,并继续向右遍历,如果一直为0就该位改为1并继续遍历;一旦遇到了1就结束程序。

过程的示意图如下: alt

具体代码如下:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param num string字符串 
     * @return string字符串
     */
    string maxLexicographical(string num) {
        // write code here
        for (int i=0;i<num.size();i++)
        {
            //找到第一个‘0’
            if (num[i]=='0')
            {
                int l = i;
                num[i] = '1';
                while ((l+1<num.size()) && num[l+1]=='0')
                {
                    l++;
                    num[l] = '1';
                }
                //注意这里在while结束后就要break跳出for循环
                break;
            }
        }
        return num;
    }
};

时间复杂度: O(N)O(N)。将字符串遍历了一遍。
空间复杂度: O(1)O(1)。没有开辟新的存储空间。