[英]How to create array [1, 2, 3, 1] from given range Q queries with N elements each [1, 3] [2, 3] [3, 4] in less than O(QN)?
我有 Q 個查詢,每個查詢包含 N 個元素。 查詢將是范圍。
[1, 3] [2, 3] [3, 4]
如果我們展平范圍查詢,我們會得到這個。
1, 2, 3, 2, 3, 3, 4
我正在嘗試找到一種解決方案來創建下面給出的數組。
[1, 2, 3, 4] --> elements in range
[1, 2, 3, 1] --> their frequency array
解釋 -> 元素 1 在范圍查詢中只出現一次,類似地,2 在范圍查詢中出現兩次,依此類推,最后 4 只出現一次。
如上所述,它給出了一組元素頻率。
但是將范圍展平並對其進行迭代以創建數組的時間復雜度為 O(QN) [1, 2, 3, 2, 3, 3, 4] --> [1, 2, 3, 1]
我沒有優化它,我的問題是 - 我們如何才能以盡可能低的時間復雜度(至少小於 O(QN)?
我看到了兩種可能的方法。 第一個假設通過每個查詢的全部范圍進行一次迭代。 它在小范圍內有效,但並不比 O(QN) 好:
int[] freqCount1 (final List<int[]> queries){
Map<Integer, Integer> results = new HashMap<>();
for(int[] q : queries){
for(int i = q[0]; i <= q[1]; i++){
if (!results.containsKey(i)){
results.put(i, 1);
}
else {
results.put(i, results.get(i) + 1);
}
}
}
int[] count = new int[results.size()];
List<Integer> resultsValues = new ArrayList<>(results.values());
for (int i = 0; i < resultsValues.size(); i++){
count[i] = resultsValues.get(i);
}
return count;
}
第二種方法假定完全確定所有查詢的范圍,然后遍歷范圍中的每個元素,檢查它是否包含在每個查詢中。 在這種方法中,您不需要遍歷每個查詢的全部范圍,所以我相信這低於 O(QN),假設范圍在某種程度上重疊。
int[] freqCount2 (final List<int[]> queries){
int min = queries.stream().map(q -> q[0]).min(Integer::compareTo).get();
int max = queries.stream().map(q -> q[1]).max(Integer::compareTo).get();
int range = max - min + 1;
int[] entries = new int[range];
List<Integer> countList = new ArrayList<>();
for (int i = 0; i < range; i++){
entries[i] = i + min;
countList.add(0);
}
for (int[] q : queries) {
for (int i = 0; i < range; i++) {
if (entries[i] >= q[0] && entries[i] <= q[1]) {
countList.set(i, countList.get(i) + 1);
}
}
}
List<Integer> countListFiltered = countList.stream()
.filter(integer -> integer > 0)
.collect(Collectors.toList());
int[] count = new int[countListFiltered.size()];
for (int i = 0; i < countListFiltered.size(); i++){
count[i] = countListFiltered.get(i);
}
return count;
}
我在實踐中進行了測試,並以您的示例為例,第一種方法要快得多,但是由於范圍長且重疊,第二次獲勝(我測試了[4,50000] [300000,500000] [2,100000] [3,800] [5,100000] [6,100000] [70000,900000] [8,100000]
)
使用掃描應該可以達到 O(Q log(Q) + N) 。 基本思想是將區間放在數軸上。 間隔的開始和結束按升序處理,同時保持“尚未關閉的間隔”的計數。
下面的代碼演示了這一點:
import java.util.*;
import java.util.stream.IntStream;
public class Ranges {
public static void main(String[] args) {
List<Range> ranges = List.of(
new Range(2,7), new Range(1,6), new Range(7, 8), new Range(1, 9)
);
System.out.println(ranges);
List<Event> events = createEvents(ranges);
int open = 0;
int start = 0;
for (Event event : events) {
switch (event.type()) {
case START:
if (open > 0) {
int end = event.value();
output(start, end, open);
start = end;
} else {
start = event.value();
}
open++;
break;
case STOP:
int end = event.value();
if (open == 1 || start != end) {
output(start, end + 1, open);
start = end + 1;
}
open--;
break;
}
}
}
static List<Event> createEvents(List<Range> ranges) {
List<Event> events = new ArrayList<>();
for (Range range : ranges) {
events.add(new Event(EventType.START, range, range.start()));
events.add(new Event(EventType.STOP, range, range.end()));
}
Collections.sort(events);
return events;
}
static void output(int start, int end, int count) {
IntStream.range(start, end).forEach(value -> System.out.printf("%d %d \n", value, count));
}
/* helper types */
enum EventType {START, STOP}
static class Range {
int start, end;
Range(int start, int end) {
this.start = start;
this.end = end;
}
int start() { return start; }
int end() { return end; }
public String toString() {
return "[" + start + ", " + end + "]";
}
}
static class Event implements Comparable<Event> {
EventType type;
Range range;
int value;
Event(EventType type, Range range, int value) {
this.type = type;
this.range = range;
this.value = value;
}
@Override
public int compareTo(Event e) {
return Integer.compare(value, e.value);
}
EventType type() { return type; }
Range range() { return range; }
int value() { return value; }
}
}
輸出
[[2, 7], [1, 6], [7, 8], [1, 9]]
1 2
2 3
3 3
4 3
5 3
6 3
7 2
8 2
9 1
(第一行是輸入;接下來每一行的數字和計數)
復雜性是通過在 O(Q log(Q)) 時間內排序並通過在 O(N) 中發出每個數字的計數來確定的。 如果我沒記錯的話,復雜度應該是 O(Q log(Q) + N)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.