所有排列中的最大和,带你认识差分数组

  • Post author:
  • Post category:其他

引入问题

给你一个数组nums,再给你一大串任意多的区间[i,j]和数字n,叫你对nums数组的区间[i,j],做+n操作,要你最后给出nums数组的值

思路:

对于每一个区间[i,j],使用一个循环,从num[i]开始,到nums[j],每个数字都+n,这样做看上去似乎行得通,但是一旦数组元素的数量非常大,区间[i,j]的跨度非常大,区间的数量非常多,非常容易导致时间超限,那我们如何来进行优化呢?

何为差分数组

差分数组被用来快速对数组某一段区间进行增加或减少操作

假设原nums数组的值为{5,7,6,3,8},计算出差分数组differen,其中differen[i] = nums[i]-nums[i-1],特殊情况differen[0] = nums[0]

 如何由差分数组还原到原数组呢?num[i] = num[i-1] + differen[i],特殊情况:nums[0] = differen[0]

 如何使用差分数组对数组的某一块区域做增加或减少的操作呢?

假设区间为[1,3],n为5,我们只需要对differen[1]+5,differen[3+1]-5,就可以了

当我们对differen[1]+5,就意味着我们对nums[1]到最后,都加了5

原因是因为num[1] = num[0] + differen[1],differen[1]加了5,导致num[1]加了5,而num[2] = num[1] + differen[2],导致num[2]也加了5,依次类推,所以我们需要在differen[3+1]-5,保证只有区间[1,3]是加5

航班预订统计

现在我们来看一下leetcode第1109题:航班预订统计

 分析题意,不难得出,n为数组大小,原数组所有元素都为0,给出区间,对这个区间做增加操作,刚刚好对应前面的差分数组

以下为参考代码:

class Solution {
    public int[] corpFlightBookings(int[][] bookings, int n) {
        // 因为原始数组全为0,所以差分数组也全为0
        int[] differen = new int[n];
        // 对差分数组做区间加法
        for(int i=0; i<bookings.length; i++){
            differen[bookings[i][0]-1]+=bookings[i][2];
            // 如果区间的右部和数组一样大,表示区间中的元素都需要加,不需要做减法截断
            if(bookings[i][1] < n){
                differen[bookings[i][1]]-=bookings[i][2];
            }
        }
        // 还原原始数组
        int[] sum = new int[n];
        sum[0] =differen[0];
        for(int i=1; i<n; i++){
            sum[i] = sum[i-1]+differen[i];
        }
        return sum;
    }
}

所有排列中的最大和

我们再来看一下第35场双周赛,第二题:所有排列中的最大和

 

 根据题意进行分析可以得知:本题需要求的是,requests数组中,按照区间中数字出现次数排序,然后将nums数组排序,将nums数组中大的数和区间中出现数字次数多的相乘,即是最后的答案,下面我们拿第三个用例来分析

 在题目中我们唯一的难点就是,如何快速计算requests中,每个区间中数字出现的次数,刚刚好,我们今天学习了差分数组,正好派上用场,这里我们可以把原始数组当成是全是0,每个区间,都增加1

参考代码:

class Solution {
    public int maxSumRangeQuery(int[] nums, int[][] requests) {
        int ans = 0;
        // 排序数组,为后续乘法做准备
        Arrays.sort(nums);
        // 创建差分数组
        int count[] = new int[nums.length];
        int index = 0;
        // 使用差分数组进行区间加法
        for(int i=0; i<requests.length; i++){
            count[requests[i][0]]+=1;
            if(requests[i][1]+1 < nums.length){
                count[requests[i][1]+1]-=1;
            }
        }
        // 原始数组
        int sum[] = new int[nums.length];
        // 利用差分数组计算原始数组
        sum[0] = count[0];
        for(int i=1; i<nums.length; i++){
            sum[i] = sum[i-1]+count[i];
        }
        // 原始数组排序
        Arrays.sort(sum);
        // 开始计算大小
        int sort = nums.length-1;
        for(int i=sum.length-1; i>=0; i--){
            if(sum[i] == 0){
                break;
            }
            ans+=nums[sort--]*sum[i];
            ans = ans%1000000007;
        }
        return ans;
    }
}

 


版权声明:本文为OnlyloveCuracao原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。