Leetcode之一起攻克前缀和(前缀树)

前言

Leetcode中涉及前缀和/前缀树的题目较少,不过一遇到就容易GG,也没有人去专门整理这方面的题,本篇来整理Leetcode中的前缀和与前缀树方面的题目与题解。

前缀和题目

560. 和为K的子数组

题目链接

思路

这道题可以使用O(n^2)的思路,就是让每个nums[i]作为头然后往后累加判断是否加和等于k。但本题可以有更好的思路,可以使用前缀和来解决这道题。
先来看下面这句话:
nums[0]需要的加和有,nums[0],nums[0]+nums[1],nums[0]+nums[1]+nums[2],
nums[1]需要的和有nums[1],nums[1]+nums[2],
nums[2]需要的有nums[2],
而nums[1]+nums[2]可以相当于sum2-sums0,nums[1] = sum1-sum0,nums[2] = sum2-sum1
这样其实只需要遍历一次,同时记录sum数组即可收获所有我们需要计算的值,同时在判断时也可以一次判断,判断是否存在i满足:sum[i]-sum[j]=k,这样就说明j-i之间的值加和等于k,值得注意的是,j不一定是1个值,所以要加进去的次数是sum[j]的次数,而不是加1。
举例:比如[1,2,3,4,-4,4,5],k=5,
其中 sum[3]=10,sum[5]=10,
当sum=15(i=6时),sum-k=10,这时存在两个所以要加两次,也就是说明有两个和可以为5,分别为位置从(3,6]和(5,6]

代码

class Solution {
    public int subarraySum(int[] nums, int k) {
       
        int times = 0;
        Map<Integer,Integer>map = new HashMap<>();
        //防止有从头开始的连续加和直接等于k,比如【1,1,1】,k=2中的前面两个1
        map.put(0,1);
        int sum = 0;
        for(int i=0;i<nums.length;i++)
        {
            sum += nums[i];
            int need = sum-k;
            //是否存在sum[j],满足sum[i]-sum[j]=k
            if(map.containsKey(need))
                times += map.get(need);
            //map 中key对应的value可能不是1。
            //比如[1,2,3,4,-4,4,5],k=5,sum[3]=10,sum[5]=10,当sum=15(i=6时,sum-k=10,这时存在两个所以要加两次,也就是说明有两个和可以为5)
            //分别为位置从(3,6]和(5,6]
            map.put(sum,map.getOrDefault(sum,0)+1);
        }
        return times;
    }
}

5248. 统计「优美子数组」

题目链接

思路

本题和上一题类似,题目中要统计奇数个数为k的子数组个数,可以将奇数置为1,偶数置为0,这样就变成了统计和为k的子数组个数,就与上一道题相同了。

代码

class Solution {
    public int numberOfSubarrays(int[] nums, int k) {
        //使用前缀和的原因也是子数组要连续
        //使用前缀和(将奇数变为1,偶数为0)
        //sum[i] = sum[i-1]+num;
        //如果存在sum[i]-k>0,那就说明肯定存在一段数组的和等于k
        //如果从(j,n]的和为k ,那么当我们找到sum[n]的时候,就会存在sum[n]-k=sum[j],此时times就加上sum[j]的个数,
        //因为这里j可能不是一个值,
        Map<Integer,Integer>map = new HashMap<>();
       int sum = 0;
        map.put(0,1);
        int temp = 0;
        for(int i=0;i<nums.length;i++)
        {
            if(nums[i]%2!=0)
            {
                sum += 1;
                }
            if(sum>=k)
            {
                //和为j
                int j = sum-k;
                //找和为j的个数
                temp+=map.get(j);
            }
            map.put(sum,map.getOrDefault(sum,0)+1);
        }
        return temp;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章