|
|
public class ListUtils {
public static List<Integer> mergeSortedLists0(@NonNull List<Integer> sortedList1, @NonNull List<Integer> sortedList2) {
var resultList = new ArrayList(sortedList1.size() + sortedList2.size());
var i = 0;
var j = 0;
while (i < sortedList1.size() && j < sortedList2.size()) {
var elem1 = sortedList1.get(i);
var elem2 = sortedList2.get(j);
if (elem1 <= elem2) {
resultList.add(elem1);
++i;
} else {
resultList.add(elem2);
++j;
}
}
while (i < sortedList1.size()) {
resultList.add(sortedList1.get(i++));
}
while (j < sortedList2.size()) {
resultList.add(sortedList2.get(j++));
}
return resultList;
}
// more generic implementation:
// * not to assume input lists are ArrayLists (use index to get value from a linked list is slow)
// * use template to support different kinds of element types in lists
public static <T extends Comparable> List<T> mergeSortedLists(@NonNull List<T> sortedList1, @NonNull List<T> sortedList2) {
var resultList = new ArrayList<T>(sortedList1.size() + sortedList2.size());
var iter1 = sortedList1.iterator();
var iter2 = sortedList2.iterator();
T elem1 = null;
T elem2 = null;
while (true) {
if (elem1 == null && iter1.hasNext()) {
elem1 = iter1.next();
}
if (elem2 == null && iter2.hasNext()) {
elem2 = iter2.next();
}
if (elem1 == null && elem2 == null) {
break;
}
if (elem1 != null && (elem2 == null || elem1.compareTo(elem2) <= 0)) {
resultList.add(elem1);
elem1 = null;
} else {
resultList.add(elem2);
elem2 = null;
}
}
return resultList;
}
}
第二种实现方法中的条件分析:
#1: e1 == null && e2 == null: break #2: e1 == null && e2 != null: add e2 #3: e1 != null && e2 == null: add e1 #4: e1 != null && e2 != null && <e1, e2>: add e1 #5: e1 != null && e2 != null && <e2, e1>: add e2在程序中,#1是一个分支;#3和#4是一个分支;其余的(#2和#5)是一个分支。 这个算法的想法很简单,但程序编写起来意外地麻烦,感觉难以编写得简洁明快。第二种方法中之所以判断元素为null与否,主要是因为Java中的Iterator不像C++ STL中的那样把取值和移动分开(分别用*和++操作符),而是合为一体了(next()方法),所以使得该问题的实现有点麻烦。用C++来写的话,就好多了:
template <typename T>
std::vector<T> mergeSortedList(std::vector<T>& sortedList1, std::vector<T>& sortedList2)
{
typename std::vector<T>::iterator iter1 = sortedList1.begin();
typename std::vector<T>::iterator iter2 = sortedList2.begin();
typename std::vector<T> resultList;
while (iter1 != sortedList1.end() && iter2 != sortedList2.end()) {
if (*iter1 < *iter2) {
resultList.push_back(*iter1++);
}
else {
resultList.push_back(*iter2++);
}
}
while (iter1 != sortedList1.end()) {
resultList.push_back(*iter1++);
}
while (iter2 != sortedList2.end()) {
resultList.push_back(*iter2++);
}
return resultList;
}
第一种实现方法比较简洁,而且它也可以改写成用模板的通用程序,但是如果表是链表,随机存取是很慢的。如果一定要用这种写法,则宁可牺牲一点存储空间,把链表拷贝到ArrayList中再处理,会快得多。
对,并且只储存非零系数。对于这个例子,则只需储存两个结点:{<1, 0>, <2, 10000>}。
多项式加法: 假设有多项式P(n+1个系数)和Q(m+1个系数),而且m<n,那么其和为:
P(x, n): {p(0), p(1), p(2), ..., p(n)}
P(x, n): {q(0), q(1), q(2), ..., q(m)}
m < n
R(x, n) = P + Q: {p(0) + q(0), p(1) + q(1), ..., p(m) + q(m), p(m+1), ..., p(n)}
显然,其时间为O(n)。
这种普通的多项式适合用顺序存储的表来表示。对于项比较“稀疏”的那种多项式,则适合用链表来表示。其相加的算法为:从两个表的表头开始各取一个元素,比较其指数:把小的那个放入新表。如果两个相等,则将其系数相加,结果不为0的话,放入新表。这跟前面的合并有序表的算法类似。
多项式乘法:可以转换为多个多项式加法。用一个多项式的每一项去乘另一个多项式,就得到一个新的多项式。最后把所有的多项式按上述“稀疏”多项式的要领相加即可。