2020/4/21 统计「优美子数组」
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-number-of-nice-subarrays
题目 给你一个整数数组 nums 和一个整数 k。
如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。
请返回这个数组中「优美子数组」的数目
新手分析
第一眼看题目,首先想到的是暴力法,全部列出,然后来个判断,但这一般都会超时,不好
下面开始思考,摸索一下例题的规律
例二给的启示就是整个数组如果没有奇数
就直接 return 0
例一告诉了我们题目的意思
那么看例三,只给了答案,分析一下
大致想到的是k=2,而整个数组就两个奇数,那就把数组框到1221,发现数组规律在1221的左右分别有三个2,也就是在1221的基础上,左边可以0,1,2,3个2,右边也是,在左边0,1,2,3个2的时候,右边也分别可以0,1,2,3个2,所以是4x4=16
那么算法的话,因为正好k=当前的奇数个数,所以可能具有特殊性。
此时我们再来看示例1
用我们刚刚想的,找到k个奇数的最小数组,但示例1中,找到的最小数组之后,发现只有一个2,也就是说找到了也只能最多一个,反而后面是1,可以遍历过去,那么就又想到,找最小满足数组?然后在结合刚刚找到后怎么做?想到这,我决定自己来个示例看看
圈出最小满足的数组,有5个,先看第一个,左边没有东西,右边是1,那他就直接结束,就一个,第二个圈,左边有2,右边2个2,那就是多出2x3=6个,再看第三个,左边1,右边1,那就是一个直接结束,第四个,左边2个2,右边1,那就是3个,因为右边是1不用考虑,左边分别是0,1,2个2,就是3个,第五个圈也就是最后一个圈,显然也就一个,因为左边1,右边啥都没,所以答案应该就是1+6+1+3+1=12
想到这,可能我发现了此题就是找这最小的数组,也就是没有多余的偶数在外,也就是左右两边肯定是1
,然后满足k,往里面塞k-2个1,OK好像有思路了。
哦,我们忘了k>=1,所以还得说下k=1,这个简单,也就是圈画成一个1一个圈
化繁为简,先不考虑那么多,慢慢来捋捋
k=1,找1(化繁为简,先说1 )
k>1 ,找1xxx1形式,xxx里满足k-2个1.
找完后,每个数组开始找旁边的2,一直找到又到1.就结束,然后左边有n个2,右边有n个2,结果就是(n+1)(n+1),验算,没错对的
化简为繁
前面找的1就是找奇数,找的2就是找偶数
难题重现
1.找到1xxx1形式
2.找到1xxx1形式后找2
品味难题
怎么找1xxx1形式呢,这时候就想到一个题目,删除最外括号,利用count,因为括号只有左和右,发现左括号,就加一,不然减一,这样0就是说明左右括号一致,那么来到这题,我没想到利用count,count为k结束,找k个奇数,每一个奇数都是开始寻找的点,
class Solution:
def numberOfSubarrays(self, nums: List[int], k: int) -> int:
sum = 0 #最终结果
leftevennumber = 0
rightevennumber = 0
for i in range(len(nums)):
if nums[i]%2==0: #遍历列表入股为偶数
leftevennumber+=1 #偶数就左边加一到时候用来计算多余数组
else: #遍历到奇数,开始找最小数组
count = 0 #寻找奇数个数
for j in range(i,len(nums)): #从奇数开始遍历
if count<k and nums[j]%2!=0: #没到,奇数就加1
count+=1
if (count==k)and(j==len(nums)-1):
sum+=(leftevennumber+1)*(rightevennumber+1)
leftevennumber = 0 #左右边归零
rightevennumber = 0
break
else:
continue
elif count==k and nums[j]%2==0: #到了,开始计算后面的多余偶数个数
rightevennumber+=1
if (count==k)and(j==len(nums)-1):
sum+=(leftevennumber+1)*(rightevennumber+1)
leftevennumber = 0 #左右边归零
rightevennumber = 0
break
elif count==k and nums[j]%2!=0: #超过规定奇数个数,算出当前最小数组的最多个数,结束此次最小数组的遍历
sum+=(leftevennumber+1)*(rightevennumber+1)
leftevennumber = 0 #左右边归零
rightevennumber = 0
break
elif count<k and nums[j]%2==0:
continue
elif count>k:
continue
else:
sum+=(leftevennumber+1)*(rightevennumber+1)
leftevennumber = 0 #左右边归零
rightevennumber = 0
break
return sum
结果,很遗憾,超出时间限制。
好吧,只能取看看别人怎么想的了,这题就这样失败了
高手分析