问题
Possible Duplicate:
Fast Algorithm to Quickly Find the Range a Number Belongs to in a Set of Ranges?
Given a list of range of numbers that are non-overlapping and sorted (rangeList), and a number, write an efficient algorithm to find first whether this number exists in (some range in) rangeList and if it does exist, return the correct range.
For example rangeList = [(-1, 200), (300, 2000), (2011, 2300)]
Query 1: 1000 -> (True, (300, 2000) ) since 1000 lies between 300 and 2000.
Query 2: 250 -> (False, (None, None) ) since no 250 does not exist in any range in the list.
The best algorithm I have come up with is log N using binary search. This feels like a very common problem especially for Longitude/Latitude based searches. Any ideas to make this better than log N?
回答1:
I'm not sure this will accomplish what you want, but it's a shot. It would involve an O(n) preprocessing step, and in return would offer a chance at O(1) runtime for any given query balanced against space complexity (via the parameter c). If your rangeList changes frequently, this will probably not be helpful.
Preprocessing steps:
Find the "total range" of the list of ranges (lowest acceptable value and highest, though there will be gaps in between). O(1)
Select a concentration parameter c (integer) for how many points you'd like to evaluate in that range. O(1)
Create a mapping function that maps integers [1, c] to the total range found in step 1, and can also do the inverse (this is no more complicated than a Celsius-Farenheit conversion). also O(1)
Using the mapping function, determine the points in the total range that correspond to [1, c]. Scan through the list of ranges, evaluating these points as you go, storing the answers ( (True, (300, 2000)), etc.) in an array of length c (let's call the array "Evaluated"). O(n + c)
Upon receiving a query:
Use the mapping function to convert the query number in the "total range" -> [1, c] direction. If the converted number falls outside the range [1, c], return (False, None, None). O(1)
Take the ceiling and floor of the converted number, which will give you two integers a and b. Compare Evaluated[a] and Evaluated[b]. If they contain the same answer, return it (if your converted number was already an integer, return Evaluated[converted number] directly). O(1)
If Evaluated[a] and Evaluated[b] give different answers, you have to do a binary search. But you can at least start the search at halfway between a and b, mapped back into "total range".
来源:https://stackoverflow.com/questions/8262606/dynamic-range-search