欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

记录一道题

程序员文章站 2022-03-09 16:17:19
...

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

题目描述

记录一道题

示例

记录一道题

解法思路

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