【算法】力扣每日一题20231108最长平衡子字符串

98 阅读3分钟

2609. 最长平衡子字符串 - 力扣(LeetCode)

我的代码

菜狗一只,用了一个小时暴力AC了🥲

一开始暴力思路都没有,看了提示。

1.Consider iterating over each subarray and checking if it’s balanced or not.

2.Among all balanced subarrays, the answer is the longest one of them.

双层for取子串,check是否是平衡字符串。

最朴素的统计‘0’和‘1’的个数,比较是否相等。截取前半部分判断0是否都在1前面。

如果子字符串的长度是偶数,必定不是子字符串。

class Solution {
    public int findTheLongestBalancedSubstring(String s) {
        if(s==null || s==" "){
            return 0;
        }
        int res = 0;
        for(int i=0;i<s.length();i++){
            for(int j=0;j<i;j++){
                String ss = s.substring(j,i+1); //substring左闭右开
                if(check(ss)){
                    res = Math.max(res,i-j+1); //长度i-j+1
                }                                
            }
        }
        return res;
    }
    public static boolean check(String s){
    	if(s.length()%2 !=0 )return false;
    	int n=s.length();
        int cl=0;
        int cy=0;
        for(int i=0;i<n;i++){
        	if(s.charAt(i) == '0') cl++;
            else if(s.charAt(i) == '1') cy++;  
        }
        //要保证0在1前面
        String s1 = s.substring(0,n/2);
        int sum1 = 0;
        for(int i=0;i<s1.length();i++) {
        	sum1+=(s1.charAt(i)-'0');
        }
        
        if((cl == cy)&&(sum1==0)){
            return true;
        }
        return false;
    }
}


大佬代码

解法一:暴力枚举

同样的暴力枚举,为何大佬的代码如此简洁?

  • 别用substring,既然单写check函数,为何不直接把边界当作参数
  • 只统计1的个数,判断乘2是否等于字符串长度
  • else if 保证0出现1之前
class Solution {
    public int findTheLongestBalancedSubstring(String s) {
        int n = s.length();
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (check(s, i, j)) { 
                    ans = Math.max(ans, j - i + 1);
                }
            }
        }
        return ans;
    }

    private boolean check(String s, int i, int j) {
        int cnt = 0;
        for (int k = i; k <= j; ++k) {
            if (s.charAt(k) == '1') {
                ++cnt;
            } else if (cnt > 0) {
                return false;
            }
        }
        return cnt * 2 == j - i + 1;
    }
}

作者:ylb
链接:https://leetcode.cn/problems/find-the-longest-balanced-substring-of-a-binary-string/solutions/2517465/python3javacgorusttypescript-yi-ti-shuan-twu7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解法二:优化枚举

  • 一层for循环
  • 如果是0,
    • one>0 ,清零,+1
    • one<0 , +1
  • 如果是1,更新长度max,0或1个数最小的两倍。
class Solution {
    public int findTheLongestBalancedSubstring(String s) {
        int zero = 0, one = 0;
        int ans = 0, n = s.length();
        for (int i = 0; i < n; ++i) {
            if (s.charAt(i) == '0') {
                if (one > 0) {
                    zero = 0;
                    one = 0;
                }
                ++zero;
            } else {
                ans = Math.max(ans, 2 * Math.min(zero, ++one));
            }
        }
        return ans;
    }
}

作者:ylb
链接:https://leetcode.cn/problems/find-the-longest-balanced-substring-of-a-binary-string/solutions/2517465/python3javacgorusttypescript-yi-ti-shuan-twu7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这个代码更特么优雅,优化的思路差不多。思路解释直接引用原作者了。

使用变量 idx 对 s 进行遍历。在每轮处理过程中,按照如下流程进行:

    1. 先统计连续段 0 的长度,记为 a;再统计连续段 1 的长度,记为 b(此操作满足:子串中 0 均在 1 前面)
    1. 在 a 和 b 中取较小值,进行乘 222 操作,作为当前平衡子字符串的长度,用于更新答案(此操作满足:子串中 0 和 1 数量相同)
    1. 从当前轮的结束位置 idx,再进行下轮处理(重复步骤 111 和步骤 222),直到 s 处理完成
class Solution {
    public int findTheLongestBalancedSubstring(String s) {
        int n = s.length(), idx = 0, ans = 0;
        while (idx < n) {
            int a = 0, b = 0;
            while (idx < n && s.charAt(idx) == '0' && ++a >= 0) idx++;
            while (idx < n && s.charAt(idx) == '1' && ++b >= 0) idx++;
            ans = Math.max(ans, Math.min(a, b) * 2);
        }
        return ans;
    }
}

作者:宫水三叶
链接:https://leetcode.cn/problems/find-the-longest-balanced-substring-of-a-binary-string/solutions/2517437/gong-shui-san-xie-on-shi-jian-o1-kong-ji-i8e7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

总结

  1. 统计两个数量是否相等,可以转换为统计一个数量*2,往往会使代码更简洁
  2. 看情况可以把子串坐标作为check函数参数,代替substring
  3. 遍历可以试试多用用while,比如idx=0,while(idx<0){ }