【问题描述】5457. 和为奇数的子数组数目[中等]
【解答思路】
1. 动态规划
第 1 步:设计状态
dp[i][0] 记录以arr[i]结尾的和为奇数数量
dp[i][1] 记录以arr[i]结尾的和为偶数数量
第 2 步:状态转移方程
for(int i=1;i<n;i++){if(arr[i]%2==0){dp[i][0]=dp[i-1][0];dp[i][1]=dp[i-1][1]+1;}else{dp[i][0]=dp[i-1][1]+1;dp[i][1]=dp[i-1][0];}}
第 3 步:考虑初始化
if(arr[0]%2==1){dp[0][0]=1;}else{dp[0][1]=1;}
第 4 步:考虑输出
遍历dp[i][0]相加
for(int[] k:dp){res=(res+k[0])%base;}return res;
时间复杂度:O(N^2) 空间复杂度:O(1)
static int base=1000000007;public int numOfSubarrays(int[] arr) {int n=arr.length;int res=0;int[][] dp=new int[n][2];if(arr[0]%2==1){dp[0][0]=1;}else{dp[0][1]=1;}for(int i=1;i<n;i++){if(arr[i]%2==0){dp[i][0]=dp[i-1][0];dp[i][1]=dp[i-1][1]+1;}else{dp[i][0]=dp[i-1][1]+1;dp[i][1]=dp[i-1][0];}}for(int[] k:dp){res=(res+k[0])%base;}return res;}
2. 前缀和(和动态规划类似)
如果当前的和为1,那么找到前缀和为0的,在这一段中,和就为奇数
因为前缀和为0的变成前缀和为1的,加上当前的数肯定是一个奇数
同理,如果当前的和为0,那么找到前缀和为1的,在这一段中,和就为奇数
我们只需要统计前缀和为0和1的个数即可
时间复杂度:O(N) 空间复杂度:O(1)
class Solution {public int numOfSubarrays(int[] arr) {int[] cnts = new int[2];int cur = 0;int ans = 0;cnts[0] = 1;int mod = 1000000007;for(int x : arr){//查看当前的前缀和cur = (cur + x) % 2;//结果加上前缀和相反的个数ans += cnts[1 - cur];//前缀和为cur的个数++cnts[cur]++;ans %= mod;}return ans % mod;}
}
【总结】
1. 动态规划流程
第 1 步:设计状态
第 2 步:状态转移方程
第 3 步:考虑初始化
第 4 步:考虑输出
第 5 步:考虑是否可以状态压缩
2.前缀和 想清楚状态转移
3. 一开始思路 遍历子序列 后发现有重复和 瞎搞了一个多小时 原来有更好的方法 不打周赛都不知道自己有多菜
转载链接:https://leetcode-cn.com/problems/number-of-sub-arrays-with-odd-sum/solution/dong-tai-gui-hua-by-zhan-zai-yue-guang-xia-3/
转载链接:https://leetcode-cn.com/problems/number-of-good-ways-to-split-a-string/solution/javaer-fen-by-dui-fang-zheng-zai-jiang-hua-2/