【在线编程产品介绍】
阿里云开发者社区在线编程:
免费刷题大神器,助你拿到好offer
周赛月赛不停歇,做题还能领奖品
大赛笔试全真题,常做常新有惊喜
点击链接开始产品体验:
https://developer.aliyun.com/coding 本文为大家介绍的是“65.Alice的01串”的解法探究。先来看一下题目内容:题目描述:
查看题目:Alice的01串Alice给了Bob一个字符串s,Alice想让Bob找出这个字符串中有多少个恰好包含了k个1的子串。请你帮助Bob计算出这些子串的个数。
输入一个正整数k,表示包含1的个数(0<=k<=10^6)和一个长度不为0的字符串,字符串的长度不超过10^6
输出一个数字,表示s中恰好包含k个1的子串的个数。
示例1
输入:
2
"01010"
输出:
4
方法 1:暴力搜索
根据题意,本题可以直接用双层循环扫描数组,找到所有的连续子串,查看每个组合是否拥有指定数量的 1。搜索可以做适当优化,比如内层循环找到超出 k 个 1 时,可以停止扫描,但本质上时间复杂度上界仍是二次幂。
时间复杂度:O(n^2)
空间复杂度:O(1)
方法 2:暴力搜索的优化,滑窗法
上面暴力法的主要缺陷是,扫描过程中有过多的无用扫描,比如寻找含有 3 个 1 的 01 串,可以在前一个含有 3 个 1 的 01 串的基础上,去掉第 1 个 1,并寻找到下 1 个 1,而不是像暴力解法一样,每次都要从头扫描。
请试图在暴力搜索二重循环的基础上,用几个标识输入串下标的变量,标识当前搜索 01 串的开头和结尾,尽可能减小时间复杂度。如果设计足够耐心的话,此方法可以达到 1 遍扫描解决的效果,但需要的分支判断会比较多。
时间复杂度:O(n)
方法 3:寻找规律
优化本题的关键是设计合理的数据结构,在方法 2 的基础上避免多余的滑窗操作和分支判断,直接利用每个串两侧赘余 0 的个数,用数学方法算出 01 串数量。记录下每个 1 出现的位置和顺序,及各个 1 之间 0 的数量,这样,只要将 k 个 1 的最短 01 串前后 0 的数量做乘积,就得到了所有含 k 个 1 的 01 串的数量,譬如:
输入:
2
"00101010"
将上面的串转化为 map 映射:
这是第几个 1 | 这个 1 到上一个 1 之间 0 的数量 |
---|---|
1 | |
3 | |
# |
首先考察第 1 个 1 和第 2 个 1 组成的最短 01 串:
"00101010"
前后分别有 2 和 1 个 0:
重点: 此时可以直接算出,第 1 个 1 和第 2 个 1 组成的 “含 2 个 1 的 01 串” 的数量为:
(2+1)*(1+1)=6
;用类似的方法继续计算第 2 和第 3 个 1 组成的 01 串数量,加到一起就得到了答案。
将上面的思路转换为代码,大致分为几步:
- 遍历输入串,用散列表,或者数组,记录下每个 1 到上个 1(也可以记录每个 1 到下个 1)的 0 的个数。
- 遍历生成的散列表或数组,同时用两个临时变量标识目标 01 串的第一个 1 和最后一个 1 的位置,直接利用他们前/后的 0 的个数做乘积。累加得到结果。
这种解法写代码的思路会相对清晰,相对解法 2 滑窗的分支判断较少。
注意: 计算时,注意需要将间隔的 0 的数量 2 和 1 分别 +1 后再彼此相乘,因为最短 01 串两侧分别不包含任何 0,也是一种符合题意的 Alice01 串。
空间复杂度:O(n)
看完之后是不是有了答题思路了呢,快来练练手吧:
65.Alice的01串在线编程周赛、月赛火热进行中,更有限时答题活动,社区定制卫衣、双肩背包等你来拿~每天都有好礼相送~点击了解周赛详情:
在线编程内测中,抢先周赛赢好礼!面试考试前,快来刷刷题!
上一篇: 笔试算法模拟题精解之“超车”的两种解法 下一篇: 笔试算法模拟题精解之“2的幂次方数”