记录一道题

这是周赛的一道第二题,一般第二题的难度还行。但今天这个给我整自闭了害
还是太菜了,记录一下

题目描述

记录一道题_第1张图片

示例

记录一道题_第2张图片

解法思路

1、最初想到的暴力

class Solution {
    public int numSub(String s) {
        int res = 0;
        for(int i = 0; i < s.length(); i++){
            for(int j = i + 1; j <= s.length(); j++){
                String tmp = s.substring(i,j);
                if(pb(tmp)){
                    res++;
                }
            }
        }
        return res % 1000000007;
    }
    //定义一个辅助函数,如果字符串全是1,则返回true,否则返回false
    private boolean pb(String tmp){
        for(int i = 0; i < tmp.length(); i++){
            if(tmp.charAt(i) == '0'){
                return false;
            }
        }
        return true;
    }
}

超时。

2、查找0的位置

我想怎么也不能死在第二题,,又想了一个思路。

class Solution {
    public int numSub(String s) {
        String tmp = "0" + s + "0";
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < tmp.length(); i++){
            if(tmp.charAt(i) == '0'){
                list.add(i);
            }
        }
        Integer[] zero = list.toArray(new Integer[list.size()]);
        long res = 0L;
        for(int i = 0; i < zero.length - 1; i++){ 
            res += ((zero[i+1] - zero[i]) * (zero[i+1] - zero[i] - 1) / 2);
        }
        return (int)res % 1000000007;
    }
}

这个还是执行出错了,问题出在我的用例都是比较小的数,所以执行起来没有问题。
但是遇到非常大的数,就会有问题。
请教了一个老哥,意识到我的乘法那里可能会超出int范围,然后取模应该用逆元。
但是我最后也没能AC。

补充:

最后发现问题是出现在计算每个区间的子数组个数那里,可能len的长度会超出int的范围,因此将len转化为long类型,就ac了。
还有这个取模这里就是每部分都取模,以防数字过大。

代码:

class Solution {
    public int numSub(String s) {
        String tmp = "0" + s + "0";
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < tmp.length(); i++){
            if(tmp.charAt(i) == '0'){
                list.add(i);
            }
        }
        Integer[] zero = list.toArray(new Integer[list.size()]);
        long res = 0L;
        for(int i = 0; i < zero.length - 1; i++){ 
            int len = zero[i+1] - zero[i];
            long count = (long)len * (long)(len - 1) / 2;
            count %= 1000000007;
            res = (res + count) % 1000000007;
        }
        return (int)res;
    }
}

3、最终方案

class Solution {
    public int numSub(String s) {
        s = s + "2";
        char[] cc = s.toCharArray();
        long cur = 0L, res = 0L;
        for(char c : cc)
        {
            if(c == '1') cur++;            
            else
            {
                res += cur * (cur + 1) / 2;
                cur = 0;
            }            
        }
        return (int)(res % 1000000007);
    }
}

想法感觉跟我上一个差不多,但是空间优化了。
一样也是在最后加了一个哨兵。
但是它计算连续1的个数,然后计算。
所以避免了大数相乘爆int的情况。

还是太菜了,要多学习。

先去吃饭了,下午整理一下逆元取模还有爆int这个问题的知识。

你可能感兴趣的:(Java)