LC1248.统计优美子数组

LC1248.统计优美子数组
image.png


思路1:滑动窗口

image.png

  • 第一反应就是滑动窗口,但是后续没什么思路,参考了甜姨@sweetiee的做法,这个博主题解写的挺清楚的。读了其他几篇题解,很清晰,推荐。
  • 设置一个滑动窗口,odd_cnt记录窗口内部的奇数数量。指向滑动窗口右边界的指针right从左向右遍历整个数组,逐个填入nums[right],如果odd_cnt == k,那么就移动左边界指针left,使得left指向“滑动窗口区间的第一个奇数”,那么,[left, right]形成的滑动窗口当中,一定有k个奇数。想要窗口滑动,就将left指向“第一个奇数”的下一个位置,此时odd_cnt == k - 1,产生滑动。
  • 滑动窗口可以不重不漏记录每一个“以left为左边界,right为右边界,且odd_cnt == k”的情况。每一个这种情况都对应若干的“优美子数组”,其统计方式如下。
  • left左边的连续的偶数,都可以作为优美子数组的起点。连续偶数的数量记为left_even_cnt。在right右边的连续的偶数,都可以作为优美子数组的终点。连续偶数的数量记为right_even_cnt
  • 每一个滑动窗口对应的优美子数组的数量为LC1248.统计优美子数组 - 图3,加的那个1说明什么都不取。

    代码1:

    1. class Solution {
    2. public:
    3. int numberOfSubarrays(vector<int>& nums, int k) {
    4. int n = nums.size();
    5. int left = 0, right = 0;
    6. int ans = 0;
    7. int cnt_odd = 0;
    8. for (right = 0; right < n; right++) {
    9. // 如果是奇数
    10. if (nums[right] & 1) {
    11. cnt_odd += 1;
    12. }
    13. // 如果有k个奇数了
    14. int rp = right + 1;
    15. int right_even_cnt = 0, left_even_cnt = 0;
    16. if (cnt_odd == k) {
    17. // 从当前right指向的位置,到下一个奇数出现的位置(或者数组的最后一个位置),偶数数量记作right_even_cnt
    18. while ((rp < n) && ((nums[rp] & 1) == 0)) {
    19. rp += 1;
    20. right_even_cnt += 1;
    21. }
    22. // left指向当前数组第一个奇数所在的位置
    23. while ((nums[left] & 1) == 0) {
    24. left_even_cnt += 1;
    25. left += 1;
    26. }
    27. ans += (left_even_cnt + 1) * (right_even_cnt + 1);
    28. // 此时left指向数组中第一个奇数,需要往后移动一位。
    29. left += 1;
    30. cnt_odd -= 1;
    31. }
    32. }
    33. return ans;
    34. }
    35. };

思路2:前缀和 + 哈希表

  • 如果奇数记为1,偶数记为0。那么,此题相当于在找“和为k的子数组”。
  • 建立前缀和数组summ。对于在数组当中找LC1248.统计优美子数组 - 图4
  • 哈希表解决两数之差的问题。哈希表recrec[summ[i]]表示summ[i]出现的次数。
  • 对于每一个summ[i]而言,都有rec[summ[i] - k]summ[j]能够和其匹配,满足LC1248.统计优美子数组 - 图5

    代码2:

    1. class Solution {
    2. public:
    3. int numberOfSubarrays(vector<int>& nums, int k) {
    4. // 前缀和 + 哈希表
    5. // 偶数记为0,奇数记为1,等于统计和为k的子数组数量。
    6. int n = nums.size();
    7. vector<int> summ(n + 1, 0);
    8. for (int i = 0; i < n; i++) {
    9. if (nums[i] & 1) {
    10. nums[i] = 1;
    11. } else {
    12. nums[i] = 0;
    13. }
    14. }
    15. for (int i = 1; i <= n; i++) {
    16. summ[i] = summ[i - 1] + nums[i - 1];
    17. }
    18. unordered_map<int, int> rec;
    19. int ans = 0;
    20. for (int i = 0; i <= n; i++) {
    21. if (rec.count(summ[i] - k)) {
    22. ans += rec[summ[i] - k];
    23. }
    24. rec[summ[i]] += 1;
    25. }
    26. return ans;
    27. }
    28. };