开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情
和为奇数的子数组数目
给你一个整数数组 arr 。请你返回和为 奇数 的子数组数目。
由于答案可能会很大,请你将结果对 10^9 + 7 取余后返回。
示例1:
输入:arr = [1,3,5]
输出:4
解释:所有的子数组为 [[1],[1,3],[1,3,5],[3],[3,5],[5]] 。
所有子数组的和为 [1,4,9,3,8,5].
奇数和包括 [1,9,3,5] ,所以答案为 4 。
示例2:
输入:arr = [2,4,6]
输出:0
解释:所有子数组为 [[2],[2,4],[2,4,6],[4],[4,6],[6]] 。
所有子数组和为 [2,6,12,4,10,6] 。
所有子数组和都是偶数,所以答案为 0 。
示例3:
输入: arr = [1,2,3,4,5,6,7]
输出: 16
示例4:
输入: arr = [100,100,99,99]
输出: 4
示例5:
输入: arr = [7]
输出: 1
提示:
1 <= arr.length <= 10^51 <= arr[i] <= 100
解题思路:
一开始用递归写,但是数组太长会报函数调用太多次的错,所以改成 for 循环就好了
- 首先明确:奇+奇=偶,奇+偶=奇,偶+偶=偶
- 倒着遍历数组
- 如果当前数是奇数,以 arr[i] 开头的和为奇数的子数组数量 = 以 arr[i + 1] 开头的和为偶数的子数组数量 + 1(自身)
- 如果当前数是偶数,以 arr[i] 开头的和为奇数的子数组数量 = 以 arr[i + 1] 开头的和为奇数的子数组数量
- 用两个临时变量存储每个节点的奇偶子数组,方便计算
我的答案:
/**
* @param {number[]} arr
* @return {number}
*/
var numOfSubarrays = function(arr) {
if (!arr.length) return 0
let res = 0
let nextOdd = 0 // 临时存放以下一个数开头的和为奇数的子数组数量
let nextEven = 0 // 临时存放以下一个数开头的和为奇数的偶数组数量
// 奇+奇=偶,奇+偶=奇,偶+偶=偶
// 倒着遍历数组,nextOdd 和 nextEven 会不断更新
for (let i = arr.length - 1; i >= 0; i--) {
if (i === arr.length - 1) {
// 最后一个数,子数组只有它自身
if (arr[i] & 1) {
res++
nextOdd = 1
nextEven = 0
} else {
nextOdd = 0
nextEven = 1
}
} else if (arr[i] & 1) {
/**
* 当前是奇数
* 以 arr[i] 开头的和为奇数的子数组数量 = 以 arr[i + 1] 开头的和为偶数的子数组数量 + 1(自身)
* 以 arr[i] 开头的和为偶数的子数组数量 = 以 arr[i + 1] 开头的和为奇数的子数组数量
*/
res += nextEven + 1;
[nextOdd, nextEven] = [nextEven + 1, nextOdd]
} else {
/**
* 当前是偶数
* 以 arr[i] 开头的和为奇数的子数组数量 = 以 arr[i + 1] 开头的和为奇数的子数组数量
* 以 arr[i] 开头的和为偶数的子数组数量 = 以 arr[i + 1] 开头的和为偶数的子数组数量 + 1(自身)
*/
res += nextOdd
nextEven++
}
}
return res % (Math.pow(10, 9) + 7)
};
最后
如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )