327. Count of Range Sum(Divide and Conquer)

题目:

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 = -2upper = 2,
Return 3.
The three ranges are : [0, 0][2, 2][0, 2] and their respective sums are: -2, -1, 2.


翻译:

给定一个整数数组nums,返回位于[lower,upper](含)的范围和的个数。
范围和S(i,j)被定义为索引i和j(i≤j)之间的num中的元素的总和,包括j和j。


注意:
O(n2)的朴素算法是微不足道的。 你必须做得更好。


例:
给定nums = [-2,5,-1],下限= -2,上限= 2,
返回3。
三个范围是:[0,0],[2,2],[0,2]以及它们各自的和为:-2,-1,2。


解题思路:

递归思路,将 arr[] 均分为两半, 后一半使用sums[] 对应表示 从中间到对应下标的和,然后将sums排序,从 middle向低循环二叉检索

在sums中符合在lower和upper中的个数。


代码展示:

#include<iostream>
#include<algorithm>
#include<vector>
#include <stdio.h>      /* printf */
#include <stdlib.h>  
using namespace std;

//快排比较函数 
int comp (const void * a, const void * b)
	{
 	 if(*(long*)a > *(long*)b ) return 1; 
 	 else if(*(long*)a < *(long*)b ) return-1; 
 	 else return 0;
	}
	
class Solution {

	//从arr[]中二叉搜索找到比 target大的元素个数 
	int findBigger(long* arr,double target,int begin,int end) {
		if(arr[end] < target) return 0;
		if(arr[begin] > target) return end - begin+1;
		int l = begin ,r = end;
		while(l<r) {
			int middle = (l+r)/2;
			if(arr[middle] < target && arr[middle+1] > target) return end-middle;
			else if(arr[middle] > target) r = middle;
			else l = middle;
		}
		return 0;
	}
	
	//递归算法 
	int countSub(vector<int>& nums,int begin,int end,int lower,int upper) {
		//递归基 
		if(begin == end) return (nums[begin] >= lower&&nums[begin] <= upper)?1:0;
		if(begin > end) return 0;
		
		int middle = (begin+end)/2;
		long sumsSecond[end-middle] = {0};// sumsSecond[i] 表示 nums 从middle 到middle+i 的和 
		long sumTemp = 0;		
		for(int i = middle+1 ;i <= end ;i++) {
			sumTemp+= nums[i];
			sumsSecond[i-middle-1] = sumTemp;
		} 
		//将后一半的迭代和排序 
		qsort(sumsSecond,end-middle,sizeof(long),comp);
		int count = 0;
		sumTemp = 0;
		
		for(int i = middle;i>=begin;i--) {
			sumTemp+= nums[i];
			count += findBigger(sumsSecond,lower-sumTemp-0.5,0,end-middle-1) -findBigger(sumsSecond,upper-sumTemp+0.5,0,end-middle-1);
		}
		return countSub(nums,begin,middle,lower,upper)+ countSub(nums,middle+1,end,lower,upper) + count;
	}
	
public:
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        int len = nums.size();
        if(len==0) return 0;
        if(len == 1) return (nums[0] >= lower&&nums[0] <= upper)?1:0;
		return countSub(nums,0,len-1,lower,upper); 
    }   
};

int main() {
	Solution p;
	int a[] = {-2, 5, -1};
	vector<int> v(a,a+3);
//	cout << v.size()<<endl;
	int lower = -2, upper = 2;
	cout <<p.countRangeSum(v,lower,upper)<<endl;
} 

题目状态:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值