【LeetCode】327. Count of Range Sum(Hard)解题报告

65 篇文章 0 订阅

【LeetCode】327. Count of Range Sum(Hard)解题报告

题目地址:https://leetcode.com/problems/count-of-range-sum/description/
题目描述:

  Given an integer array nums, return the number of range sums that lie in [lower, upper] inclusive.
Range sum S(i, j) is defined as the sum of the elements in nums between indices i and j (i ≤ j), inclusive.
  Note: A naive algorithm of O(n2) is trivial. You MUST do better than that.

Example:
Given nums = [-2, 5, -1], lower = -2, upper = 2,
Return 3.
The three ranges are : [0, 0], [2, 2], [0, 2] and their respective sums are: -2, -1, 2.

Solution1:

/*
非常非常难得一道题
最优解是分治法,还可以用treemap,treeset,segement TREE
不懂
前n项和
time : O(n^2)
space : O(n)
*/
class Solution {
    public int countRangeSum(int[] nums, int lower, int upper) {
        if(nums == null || nums.length == 0) return 0;
        TreeMap<Long,Long> treeMap = new TreeMap<>();
        treeMap.put((long)0,(long)1);
        long sum = 0;
        long count = 0;
        for(int i=0 ; i<nums.length ; i++){
            sum += nums[i];
            long from = sum - upper;
            long to = sum - lower;
            Map<Long,Long> sub = treeMap.subMap(from,true,to,true);
            for(Long value : sub.values()){
                count += value;
            }
            treeMap.put(sum , treeMap.getOrDefault(sum,(long)0)+1);
        }
        return (int)count;
    }
}

Solution2:

/*
非常非常难得一道题
最优解是分治法,还可以用treemap,treeset,segement TREE
不懂,要多看
前n项和
time : O(nlogn)
space : O(n)
*/
class Solution {
    public int countRangeSum(int[] nums, int lower, int upper) {
        if(nums == null || nums.length == 0) return 0;
        long[] sum = new long[nums.length + 1];
        for(int i=1 ; i<=nums.length ; i++){
            sum[i] = sum[i-1] + nums[i-1];
        }
        return helper(sum,new long[sum.length],0,sum.length-1,lower,upper);
    }
    private int helper(long[] sum,long[] helper,int low,int high,long lower,long upper){
        if(low >= high) return 0;
        int mid = (high + 1 - low) / 2 + low;
        int count = helper(sum,helper,low,mid-1,lower,upper)
            +helper(sum,helper,mid,high,lower,upper);
        int rangeStart = mid, rangeEnd = mid;
        for(int i=low ; i<mid ; i++){
            while(rangeStart <= high && sum[rangeStart] - sum[i] < lower)
                rangeStart++;
            while(rangeEnd <= high && sum[rangeEnd] - sum[i] <= upper)
                rangeEnd++;
            count += rangeEnd - rangeStart;
        }
        merge(sum,helper,low,mid,high);
        return count;
    }
    private void merge(long[] sum, long[] helper, int low,int mid, int high){
        int left = low, right = mid, idx = low;

        while(left < mid && right <= high){
            if(sum[left] <= sum[right]){
                helper[idx++] = sum[left++];
            }else{
                helper[idx++] = sum[right++];
            }
        }
        while(left < mid){
            helper[idx++] = sum[left++];
        }
        while(right <= high){
            helper[idx++] = sum[right++];
        }
        System.arraycopy(helper,low,sum,low,high+1-low);
    }
}

Date:2018年3月8日

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值