注意参数给的是List ,不知道实现的话get方法可能是o(n)的。一开始写了个用get的,doubt 我的时间复杂度,我说这个可能是o(n),那可能需要用iterator。考官说对那就写吧,然后秒写,这里楼主就突然傻逼了。这题相当于peeking iterator,双指针(双iterator)遍历两个list时,iter.hasNext()是不能作为跳出循环的依据的,因为有一个元素是缓存起来的,只有当那个缓存的头元素也用完了之后才能跳出循环。所以这个bug卡了十分钟都没查出来,其实非常明显的但就是先入为主觉得这怎么可能错没有注意检查这个边界条件。最后给了个test case我才恍然卧槽
Follow-up是如果输入lists里有重复,但是输出结果有重复怎么做?我就加了个while loop跳过重复元素。
public final class ListUtils{ private ListUtils(){ //do nothing } //O(n + m) runtime and O(n + m) memory where n and m are the lengths of the source lists //Uses iterators to ensure that traversal of the Lists is of optimal speed. If a List were a //LinkedList, then the .get(int) would have a runtime complexity of O(n) by itself hence the //need for iterators public static List<T extends Comparable> union(List<T extends Comparable> list1, List<T extends Comparable> list2){ if(list1 == null){ if(list2 == null){ return null; } return list2; } if(list2 == null){ return list1; } ArrayList<T> results = new ArrayList<T>(list1.size() + list2.size()); Iterator<T> list1Iter = list1.iterator(); Iterator<T> list2Iter = list2.iterator(); T list1Obj = list1Iter.next(); T list2Obj = list2Iter.next(); while(list1Obj != null && list2Obj != null){ if(list1Obj.compareTo(list2Obj) < 0){ results.add(list1Obj); list1Obj = (list1Iter.hasNext()) ? list1Iter.next() : null; } else{ results.add(list2Obj); list2Obj = (list2Iter.hasNext()) ? list2Iter.next() : null; } } while(list1Obj != null){ results.add(list1Obj); list1Obj = (list1Iter.hasNext()) ? list1Iter.next() : null; } while(list2Obj != null){ results.add(list2Obj); list2Obj = (list2Iter.hasNext()) ? list2Iter.next : null; } return results; } //O(min(n, m)) runtime complexity and O(min(n, m)) memory where n and m are the length of the lists //also uses Iterators for efficient traversal of the lists public static List<T extends Comparable> intersection(List<T> list1, List<T> list2){ ArrayList<T> results = new ArrayList<T>(); if(list1 == null || list2 == null){ return results; } Iterator<T> list1Iter = list1.iterator(); Iterator<T> list2Iter = list2.Iterator(); T list1Obj = list1Iter.next(); T list2Obj = list2Iter.next(); while(list1Obj != null && list2Obj != null){ int diff = list1Obj.compareTo(list2Obj); if(diff < 0){ list1Obj = (list1Iter.hasNext()) ? list1Iter.next() : null; } else if(diff > 0){ list2Obj = (list2Iter.hasNext()) ? list2Iter.next() : null; } else{ results.add(list1Obj); list1Obj = (list1Iter.hasNext()) ? list1Iter.next() : null; list2Obj = (list2Iter.hasNext()) ? list2Iter.next() : null; } } return results; }
问union多个list的话怎么办,我说那就merge吧,面试官说不行这个空间复杂度很高。我说那就priorityqueue吧,面试官表示满意,问了下空间时间复杂度。然后继续follow up问那就俩list union,你搞个parallel算法。楼主蒙了一下,想了两分钟,说那就第一个数组分n份,找到pivotal点在第二个数组上二分搜索该元素对应的位置,得到这些位置传给并行算法就可以了吧。面试官说行,问了下空间复杂度(我觉得并没有卵区别,还是和以前一样)
public class mergeKSortedIterator { static class iterWrapper { int currentVal; Iterator<Integer> iter; public iterWrapper(Iterator<Integer> iter) { this.iter = iter; this.currentVal = this.iter.next(); } } public static Iterable<Integer> mergeKSortedIterators(List<Iterator<Integer>> iters) { ArrayList<Integer> rs = new ArrayList<>(); Comparator<iterWrapper> cmp = new Comparator<iterWrapper>() { public int compare(iterWrapper l1, iterWrapper l2) { return l1.currentVal - l2.currentVal; } }; PriorityQueue<iterWrapper> heap = new PriorityQueue<iterWrapper>(iters.size(), cmp); for (Iterator<Integer> iter : iters) { iterWrapper iw = new iterWrapper(iter); heap.offer(iw); } while (heap.size() > 0) { iterWrapper temp = heap.poll(); rs.add(temp.currentVal); if (temp.iter.hasNext()) { temp.currentVal = temp.iter.next(); heap.offer(temp); } } return rs; } public static void main(String[] args) { List<Iterator<Integer>> iters = new ArrayList<>(); for (int i = 1; i <= 3; i++) { ArrayList<Integer> l = new ArrayList<>(); for (int j = i; j < 3 * 5; j += 3) { l.add(j); } System.out.println(l); iters.add(l.iterator()); } Iterable<Integer> rs = mergeKSortedIterators(iters); System.out.print(rs); } }