1. 程式人生 > >327. Count of Range Sum(Divide and Conquer)

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;
} 

題目狀態: