• 【前缀和】1248、统计优美子数组


    1248、统计优美子数组(Medium)

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

    示例 1:
    输入:nums = [1,1,2,1,1], k = 3
    输出:2
    解释:包含 3 个奇数的子数组是 [1,1,2,1] 和 [1,2,1,1] 。
    
    示例 2:
    输入:nums = [2,4,6], k = 1
    输出:0
    解释:数列中不包含任何奇数,所以不存在优美子数组。
    

    解题思路:

      解法一:暴力枚举

      暴力枚举的方法同样可以枚举出所有的子数组,判断每一个子数组中奇数的个数,从而得到结果,时间复杂度最优为O(n^2),一般会超出题目的时间限制,不再赘述。

      解法二:数学法

      因为在这里我们只关心子数组中奇数的个数,对于有多少个偶数并不关心,因此,可以建立一个oddIndex数组,用以依次存储所有奇数的下标索引,那么对于oddIndex数组,其中的每一个元素oddIndex[i],都可以作为子数组的一个起点,并且[oddIndex[i],oddIndex[i+k-1]]就满足正好有k个奇数。

      但是,不难想到此时找到的这个子数组头尾都是奇数,所以可以向左右两侧延伸,直到碰到奇数,这样找到的子数组同样是包含k个奇数,因为只是扩展了一些偶数。

      而扩展之后的优美子数组个数=(左边的偶数个数+1)*(右边的偶数个数+1),扩展同样基于oddIndex数组就可以方便的找到,这样就可以通过计算得到最终结果。

      解法三:前缀和(前缀奇数个数)

      这里我们看到的同样是一个子数组的问题,在【前缀和】和为K、和可被K整除的子数组中,我们介绍了涉及到子数组的两类问题,求最值动态规划,不是最值考虑前缀和。那么这里是子数组的个数的问题,和第560、974题非常类似,因此可以在前缀和上做一些考虑。

      不难看到,前缀和是前i个元素之和,而这里虽然不是求和,但是我们可以用前缀奇数个数来判断,用pre[i]表示前i个元素中奇数的个数,那么从 j 到 i 这个子数组的奇数个数可以表示为pre[i]-pre[j-1],因此恰好有k个奇数可以表示为:

      pre[i]-pre[j-1]==k

      这样,实际上就完全转化为了第560题,在遍历到某个数时,找到pre-k对应的出现次数即可。

      解法四:技巧转化

      如果我们将数组中的奇数用1表示,偶数用0表示,那么有k个奇数就可以完全转化为和为K的问题。

    代码实现:

    //解法二:数学法,时间辅助度O(n),空间复杂度O(n)
    class Solution {
        public int numberOfSubarrays(int[] nums, int k) {
            //数学法
            if(nums==null || nums.length==0)
                return 0;
            
            int res=0,len=nums.length;
            int count=0;
            int[] oddIndex=new int[len+2];
            for(int i=0;i<len;i++){
                if(nums[i]%2!=0){  //奇数
                    oddIndex[++count]=i;
                }
            }
    
            //添加两个边界值
            oddIndex[0]=-1;
            oddIndex[++count]=len;
    
            for(int i=1;i+k<=count;i++){
                res += (oddIndex[i]-oddIndex[i-1])*(oddIndex[i+k]-oddIndex[i+k-1]);
            }
            return res;
        }
    }
    
    //解法三:前缀和(前缀奇数个数),时间辅助度O(n),空间复杂度O(n)
    class Solution {
        public int numberOfSubarrays(int[] nums, int k) {
            //前缀和(前缀奇数个数)+哈希表,遍历过程中统计奇数的个数,pre[i]-pre[j-1]=k
            if(nums==null || nums.length==0)
                return 0;
            
            Map<Integer,Integer> map=new HashMap<>();
            map.put(0,1);  //前缀为0个奇数
    
            int pre=0;
            int res=0;
            for(int i=0;i<nums.length;i++){
                if(nums[i]%2!=0) //奇数
                    pre++;
                res+=map.getOrDefault(pre-k,0);
                map.put(pre,map.getOrDefault(pre,0)+1);
            }
            return res;
        }
    }
    
  • 相关阅读:
    delphi 不规则窗体与桌面宠物
    delphi窗体透明但上面的控件不透明怎么实现
    IIS错误:在唯一密钥属性“fileExtension”设置为“.json”时,无法添加类型为“mimeMap”的重复集合项
    putty连接centos慢
    centos systemd占用大量内存
    laravel 163发送邮件设置及常见错误
    laravel 163发送邮件
    laravel npm run dev 错误 npm run dev error [npm ERR! code ELIFECYCLE]
    linux 如何指定nologin用户执行命令
    laravel Method IlluminateValidationValidator::validateReuqired does not exist.
  • 原文地址:https://www.cnblogs.com/gzshan/p/12990324.html
Copyright © 2020-2023  润新知