鉴于数字流,如1,3,5,4,6,9,我被要求以1,3-6,9打印它们。我的方法是在minHeap中保存最小2个数字,在minHeap中保存最多2个数字。我提出了以下解决方案。您有什么建议可以让它更优化吗?它的时间复杂度是O(nlogn)。
public static ArrayList<Integer> mergingMiddleNums (int[] arr){
if (arr == null || arr.length < 3){
throw new IllegalArgumentException();
}
ArrayList<Integer> result = new ArrayList<>();
Queue<Integer> minHeap = new PriorityQueue<>();
Queue<Integer> maxHeap = new PriorityQueue<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer num1, Integer num2) {
return num2-num1;
}
});
for (int i = 0 ; i < 2 ; i++){
minHeap.add(arr[i]);
}
for (int i = 0 ; i < 2 ; i++){
maxHeap.add(arr[i]);
}
for (int i = 2 ; i <arr.length; i++){
if(arr[i] > minHeap.peek()){
minHeap.poll();
minHeap.add(arr[i]);
}
}
result.add(minHeap.poll());
result.add(minHeap.poll());
for (int i = 2 ; i <arr.length; i++){
if(arr[i] < maxHeap.peek()){
maxHeap.poll();
maxHeap.add(arr[i]);
}
}
result.add(maxHeap.poll());
result.add(maxHeap.poll());
Collections.sort(result);
return result;
}
答案 0 :(得分:2)
这取决于您的输出是否需要流。让我们从非流式输出开始,因为您当前的实现解决了这个问题。
您的代码的总体复杂性最多只能是O(nLog(n)),但您可以通过将每个传入的数字存储在集合中,将其转换为数组并对其进行排序来从根本上简化您的实现,然后按顺序扫描项目以识别连续范围。这里最昂贵的操作是sort,它将定义你的运行时。为了节省空间,您可以使用集合或堆集合来避免存储重复项(其形成将位于O(nLog(n))附近 - 这是相同的运行时,在O的总运行时间内仍然折叠(nLog( n))的
如果您的代码需要与输出一起流式传输,也就是说,在形成时打印范围,并且只要遇到下一个数字并不直接与当前范围相邻,就可以移动到下一个范围,您可以这样做在O(n)中,当你去的时候存储当前范围的数字边界,如果当前检查的数字不在边界内或在边界内,则打印和重置它们,或者如果是,则扩展边界。
答案 1 :(得分:1)
一种可能的实现方式是使用哈希表来存储输入值中是否存在每个整数。然后,它只是从最小值迭代到最大值,并使用哈希表来找出数字簇的位置。
这种实现基本上是O(n),其中n = max-min(而不是列表中的项目数)。因此,如果您在一个相当小的值范围内有许多数字,那么您可能比基于排序的方法更好。
import java.util.HashMap;
import java.util.Map;
class Test {
private int min=0, max=-1;
private Map<Integer,Integer> map=new HashMap<Integer,Integer>();
public static void main(String args[]) {
int[] input={1,3,5,4,6,9};
Test t = new Test();
t.readNumbers(input);
t.outputRanges();
}
public void readNumbers(int[] values) {
// Get min and max values, and store all existing values in map
for(int v:values) {
if(first || v<min) min=v;
if(first || v>max) max=v;
first=false;
map.put(v, 1);
}
}
public void outputRanges() {
// Iterate from min to max and use map to find out existing
// values
int last=min-2;
boolean inRange=false;
first=true;
for(int i=min;i<=max;++i) {
if(map.get(i)==null) continue;
if(i==last+1) {
inRange=true;
} else {
if(inRange) {
closeRange(last);
inRange=false;
}
output(i);
}
last=i;
}
if(inRange) closeRange(last);
}
private boolean first;
private void commaUnlessFirst() {
if(!first) System.out.printf(",");
first=false;
}
private void output(int i) {
commaUnlessFirst();
System.out.printf("%d", i);
}
private void closeRange(int i) {
System.out.printf("-%d", i);
}
}