327_Count of Range Sum

Description:

Given an integer array nums, return thenumber of range sums that lie in [lower, upper] inclusive.

Range sum S(i, j) is defined as the sum ofthe elements in nums between indices i and j (i ≤j), inclusive.

Note:

A naive algorithm of O(n2) is trivial. YouMUST 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.

Tags:Divide and Conquer, Binary Search Tree

题意理解

这道题在说什么?

给定一个整数的数组 int[]nums, 给出一个范围区间[lower,upper].

找出数组中这一样一些子数组,他们的元素和在给定的区间内,并求出有多少个这样的子数组。如:int[j-i] sub_nums = [nums[i], nums[i+1],…, nums[j]] (i<=j),并且lower<=sum(for item in sub_nums) <=upper, 找出有多少个这样的sub_sums.

思路探讨:

1.      枚举:简单粗暴如我,最先想到的就是将所有的情况遍历一遍。

比如:给定  int[n] nums, 遍历

nums[0], nums[0]+nums[1],nums[0]+nums[1]+nums[2],……..,  nums[0] +nums[1]+nums[2]+…+nums[n-1];

nums[1], nums[1]+nums[2],… nums[1]+nums[2]+…+nums[n-1];

……………………

nums[n-1]

但是这种方法运算复杂度较高,O(n^2),不符合题目要求。故放弃。

 

第一种方法虽然在本题中不能用,却依然给我们提供一些解题思路。

如果我们定义新数组int[n]sum 来表示数组nums前n项元素和的话, 即:

sum[i] = num[0]+…. +nums[i-1].

那么我们第一种思路的遍历就可以写成:

sum[0], sum[1], sum[2], ….sum[n];

sum[1]-sum[0], sum[2]-sum[0],…sum[n]-sum[0];

sum[2]-sum[1], sum[3]-sum[1], … sum[n]- sum[1];

…………………..

sum[n]-sum[n-1]

这样我们只需要求出在区间[lower,upper]中的sum[j]-sum[i]个数即可, 即:

判断是否有lower<= sum[j]- sum[i] <= upper.

而对于特定的sum[j], 若想满足上述条件, 则需要求出对应的sum[i],满足:

sum[j]-upper <=sum[i]<=sum[j]-lower.

即:对于特定sum[j],我们只需求出在区间[sum[j]-upper,sum[j]-lower]中的sum[i]的个数,我们就可求出在区间[lower,upper]中的sum[j]-sum[i]个数。

那么这道题就转换为了求数组sum中值在特定区间[sum[j]-upper,sum[j]-lower]中的元素个数问题。

值得注意的是,这里的特定区间是随着sum[j]值的变化而变化的,我想这就是这道题用Divideand Conquer作为标签之一的原因吧。

到这里我们的整体解题思路就出来了,但是在实现过程中我们需要注意,求数组在特定区间中的元素通常情况下也需要遍历数组,这样复杂度还是会很高。我们就需要提前采取手段使sum数组成为有序的。

2和3便提供了两种方法。

2.      pythonbisect:

关于pythonbisect介绍即用法请参考:

http://www.cnblogs.com/skydesign/archive/2011/09/02/2163592.html

https://docs.python.org/2/library/bisect.html

参考代码[1]如下:

import bisect
class Solution(object):
    def countRangeSum(self, nums, lower, upper):
        """
        :type nums: List[int]
        :type lower: int
        :type upper: int
        :rtype: int
        """
        sum_list, cur_sum, count = [],0,0
        for num in nums:
            cur_sum+=num  #get the sum of all numbers before current number
            if lower <=cur_sum<=upper:
                count +=1
            if not sum_list:
                sum_list.append(cur_sum)
                continue
            low = cur_sum -lower # sum[j]-sum[i] <upper -> sum[j]-upper < sum[i]
            hi = cur_sum - upper # sum[j]-sum[i] >lower -> sum[j]-lower > sum[i]
            idx_lo = bisect.bisect_right(sum_list,low)
            idx_hi = bisect.bisect_left(sum_list,hi)
            count +=abs(idx_lo-idx_hi)
            bisect.insort(sum_list,cur_sum) #insert current sum and sort the sum list
        return count

3.      BinarySearch Tree:

Java中似乎没有与bisect相对应的排序模块?

不过不要着急,TagBinary Search Tree已经为我们泄露了天机,我们可以通过二叉搜索树来实现我们的小目标(微笑)

参考代码[2]如下:

public class countOfRangeSum_327 {
	private class TreeNode{
		long val = 0;
		int count = 1;
		int leftSize = 0;
		int rightSize = 0;
		TreeNode left = null;
		TreeNode right = null;
		public TreeNode(long v){
			this.val = v;
			this.count = 1;
			this.leftSize =0;
			this.rightSize = 0;
		}
	}
	
	private TreeNode insert(TreeNode root, long val){
		if(root == null){
			return new TreeNode(val);
		}else if(root.val == val){
			root.count++;
		}else if(val < root.val){
			root.leftSize++;
			root.left = insert(root.left,val);
		}else if(val>root.val){
			root.rightSize++;
			root.right = insert(root.right,val);
		}
		return root;
	}
	
	private int countSmaller(TreeNode root, long val){
		if(root==null){
			return 0;
		}else if(root.val == val){
			return root.leftSize;
		}else if(root.val > val){
			return countSmaller(root.left,val);
		}else{
			return root.leftSize + root.count+countSmaller(root.right,val);
		}
	}
	
	private int countLarger(TreeNode root, long val){
		if(root == null){
			return 0;
		}else if(root.val == val){
			return root.rightSize;
		}else if(root.val < val){
			return countLarger(root.right,val);
		}else {
			return countLarger(root.left,val)+root.count+root.rightSize;
		}
	}
	
	private int rangeSize(TreeNode root, long lower, long upper){
		int total = root.count + root.leftSize+root.rightSize;
		int smaller = countSmaller(root,lower);
		int larger = countLarger(root, upper);
		return total - smaller - larger;
	}
	
	public int countRangeSum(int[] nums, int lower, int upper){
		if(nums.length == 0){
			return 0;
		}
		long[] sums = new long[nums.length+1];
		for(int i = 0; i < nums.length; i++){
			sums[i+1]=sums[i]+nums[i];
		}
		TreeNode root = new TreeNode(sums[0]);
		int output = 0;
		for(int i =1; i < sums.length; i++){
			output+=rangeSize(root, sums[i]-upper, sums[i]- lower);
			insert(root, sums[i]);
		}
		return output;
	}
	
}

相似问题:

https://www.quora.com/Given-an-array-of-integers-A-and-an-integer-k-find-a-subarray-that-contains-the-largest-sum-subject-to-a-constraint-that-the-sum-is-less-than-k

总结:

这道题刚看到的时候真是丈二和尚摸不着头脑,这时需要耐心地读懂题意,然后不妨从最容易想到的方法入手,相信聪明的你一定可以顺藤摸瓜找出思路的。

PS:反正说了这么多,让我自己做还是不会(微笑)。

Reference:

[1]. https://discuss.leetcode.com/topic/66098/no-bst-no-bit-o-nlogn-binary-search-python-solution-that-beats-99

[2]. https://discuss.leetcode.com/topic/34107/java-bst-solution-averagely-o-nlogn/2


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值