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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章