LeetCode 周赛:第35场双周赛(一、二题 , Java)

LeetCode 周赛:第35场双周赛(一、二题 , Java)

题目一:所有奇数长度子数组的和[1588]

题意

计算所有奇数长度的子数组的和,子数组要求是原数组中一个连续的子序列。

思路

数据量较小,暴力模拟即可,一层循环记录子数组长度,二层循环记录开始位置,三层记录子数组

class Solution {
    public int sumOddLengthSubarrays(int[] arr) {
        if(arr==null){
            return 0;
        }
        int len = arr.length;
        int sum = 0;
        for (int i = 1; i <= len; i++) {
            if(i%2==0){
                continue;
            }
            for (int j = 0; j < len-i+1; j++) {
                for (int k = j; k <j+i; k++) {
                    sum+=arr[k];
                }
            }
        }
        return sum;
    }
}

题目二:所有排列中的最大和[1589]

题意

给定一个数组nums和一个查询数组requests,nums记录若干个数字,requests记录若干个闭区间,即requests[i] = [starti, endi],每一个区间中的数字的的查询次数+1,题目要求任意排列数字使得nums数组和查询次数的乘积和最大,求最大的乘积。结果取余1000000007。

示例:nums = [1,2,3,4,5] , requests[ [1,3] , [0,1] ]

每个数字的查询次数为:[1,2,1,1,0]

对应的数字排列:[3,5,4,2,1] || [2,5,4,2,1] …

输出:19

思路

贪心,用最大的数字乘最大的查询次数然后求和,先计算出每个nums中每个数字的查询次数checks,然后再排序nums和checks,相乘求和。

如果只是简单的模拟,假设requests的长度为m,时间复杂度应为m×n。最耗时的操作是查询次数的计算,所以应该采用其他方法计算查询次数。

差分序列

通过差分序列来计算查询次数能使的查询次数的操作的时间复杂度降到m。

差分序列diff 可以这么理解:diff[i] = num[i]-num[i-1] ,简单来说就是记录前后的变化。举个例子:假设requests = [ [1,3] ],diff 的初始值为[0,0,0,0,0](因为初始每个数字的查询次数为0),那么diff的最终结果就是diff[1]++ , diff[4–] ,查询次数check[i] = diff[i]+diff[i-1]

 ^                                                ^                                             ^
 |                                                |                                             |
 |                                                |                                             |
 |        1   1   1                     diff      |                                  check      |
 |   0    0   0   0   0               =======>    |   0   1   0   0  -1   0         ======>     |  0   1   1   1   0   0
 |—————————————————————————————>                  |---------------------------->                |------------------------->
 	 0    1   2   3   4                               0   1   2   3   4   5                        0   1   2   3   4   5

差分数列的主要操作diff[1]++ , diff[4–] ,可以这么,因为最终结果**check[i] = diff[i]+diff[i-1]**是累加的,**diff[1]++的操作会使 [1 , 5)、这个区间全都受到影响即+1,因此需要另一个操作终止这个操作只需要在[4,5)上-1即可,但是因为check[i] = diff[i]+diff[i-1]**是累加的,只需要diff[4]–,这样就保证了影响的区间为[1,3],通过计算所有requests操作的差分,然后用一个累加操作计算check即可。

题解

class Solution {
    public int maxSumRangeQuery(int[] nums, int[][] requests) {
int len = nums.length;
        int request_len = requests.length;
        int diff_array[] = new int[len];

        //计算差分序列的变化
        for (int i = 0; i < request_len; i++) {
            diff_array[requests[i][0]]++;
            //特判一下以免出界
            if(requests[i][1]+1<len){
                diff_array[requests[i][1]+1]--;

            }
        }

        //根据差分序列完成区间叠加
        for (int i = 1; i < len; i++) {
            diff_array[i] = diff_array[i]+diff_array[i-1];
        }

        Arrays.sort(nums );
        Arrays.sort(diff_array);
        long sum = 0;
        for (int i = 0; i < len; i++) {
            sum+=nums[i]*diff_array[i];
            sum%=1000000007;
        }
        return (int) sum;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值