记录一道题
程序员文章站
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这个问题的知识。
上一篇: 骁龙860对比骁龙865哪个值得入手