• [LeetCode] 1248. Count Number of Nice Subarrays


    Given an array of integers nums and an integer k. A subarray is called nice if there are k odd numbers on it.

    Return the number of nice sub-arrays.

    Example 1:

    Input: nums = [1,1,2,1,1], k = 3
    Output: 2
    Explanation: The only sub-arrays with 3 odd numbers are [1,1,2,1] and [1,2,1,1].
    

    Example 2:

    Input: nums = [2,4,6], k = 1
    Output: 0
    Explanation: There is no odd numbers in the array.
    

    Example 3:

    Input: nums = [2,2,2,1,2,2,1,2,2,2], k = 2
    Output: 16

    统计优美子数组。题意是给你一个整数数组 nums 和一个整数 k。如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。请返回这个数组中「优美子数组」的数目。

    子数组的题一般可以试图往sliding window或者前缀和prefix sum上靠,本题我两种解法都给出。首先前缀和的思路是遍历input里面的每个数字,把他们的前缀和sum和出现次数加到hashmap里面,但是这一题跟560题的区别在于,560是在找一个特别的子数组的和K,而本题是在找有多少个包含K个奇数的子数组,他并不在意子数组的和或者长度是多少。所以思路是遇到奇数的时候可以把这个数字改成1,遇到偶数的时候可以把这个数字改成0。当累加prefix sum的时候,因为从0到当前位置的前缀和为sum,所以如果找到一个前缀和sum - K,则说明存在这样一个优美子数组

    时间O(n)

    空间O(n)

    Java实现

     1 class Solution {
     2     public int numberOfSubarrays(int[] nums, int k) {
     3         int res = 0;
     4         int sum = 0;
     5         HashMap<Integer, Integer> map = new HashMap<>();
     6         map.put(0, 1);
     7         for (int i = 0; i < nums.length; i++) {
     8             sum += (nums[i] % 2 == 1) ? 1 : 0;
     9             map.put(sum, map.getOrDefault(sum, 0) + 1);
    10             res += map.getOrDefault(sum - k, 0);
    11         }
    12         return res;
    13     }
    14 }

    滑动窗口的思路也比较直观。还是用76题的经典模板,有两个指针,一个start一个end。当end指针遍历到奇数的时候,K才--。当K = 0的时候,说明当前的窗口里面包含的奇数个数为K个了,此时试图移动start指针。如果当前start指针的位置上的数字是奇数的话,则K++。其他环节跟一般的滑动窗口的题的做法没有区别。

    时间O(n)

    空间O(1)

    Java实现

     1 class Solution {
     2     public int numberOfSubarrays(int[] nums, int k) {
     3         int start = 0;
     4         int end = 0;
     5         int res = 0;
     6         int count = 0;
     7         while (end < nums.length) {
     8             if (nums[end] % 2 == 1) {
     9                 k--;
    10                 count = 0;
    11             }
    12             while (k == 0) {
    13                 if (nums[start] % 2 == 1) {
    14                     k++;
    15                 }
    16                 start++;
    17                 count++;
    18             }
    19             res += count;
    20             end++;
    21         }
    22         return res;
    23     }
    24 }

    既然题目说找的是恰好K个奇数数字的子数组,那么我们可以沿用992题的思路。即最多K个奇数数字的子数组 - 最多K - 1个奇数数字的子数组 = 正好K个奇数的子数组。

    时间O(n)

    空间O(n)

    Java实现

     1 class Solution {
     2     public int numberOfSubarrays(int[] nums, int k) {
     3         return helper(nums, k) - helper(nums, k - 1);
     4     }
     5 
     6     private int helper(int[] nums, int k) {
     7         int start = 0;
     8         int end = 0;
     9         int res = 0;
    10         while (end < nums.length) {
    11             if (nums[end] % 2 == 1) {
    12                 k--;
    13             }
    14             end++;
    15             while (k < 0) {
    16                 if (nums[start] % 2 == 1) {
    17                     k++;
    18                 }
    19                 start++;
    20             }
    21             res += end - start + 1;
    22         }
    23         return res;
    24     }
    25 }

    前缀和prefix sum题目总结

    滑动窗口类题目总结

    LeetCode 题目总结

  • 相关阅读:
    本地通知
    常用颜色RGB、灰度值
    AFNetworkingErrorDomain 错误解决方法
    给iOS开发新手送点福利,简述UIPikerView的属性和用法
    给iOS开发新手送点福利,简述UIImagePickerController的属性和用法
    给iOS开发新手送点福利,简述UIDatePicker的用法
    iOS线程开发小结
    给iOS开发新手送点福利,简述文本属性Attributes的用法
    给iOS开发新手送点福利,简述UIScrollView的属性和用法
    给iOS开发新手送点福利,简述UITableView的属性和用法
  • 原文地址:https://www.cnblogs.com/cnoodle/p/12742098.html
Copyright © 2020-2023  润新知