所以在这个Android应用程序中,我有两个带有电话号码的列表。我想找出两者中的常见数字。蛮力方式是N ^ 2。我不能使用HashSets
(我猜),因为数字可以采用不同的格式。所以我最好的选择是使用PhoneNumberUtils.compare
。 (它匹配不同格式的数字。例如,对于" +91 9413294132"以及" 09413294132"返回true;
我想要一种有效的方式,因为列表太大了。一个是我的数据库,另一个是用户的联系人。所以基本上我想知道在我的数据库中注册了哪些号码。 (也许WhatsApp发现谁在WhatsApp上的方式相同)。我真的很感激任何努力。感谢。
答案 0 :(得分:1)
这取决于你是否关心记忆/时间或两者。
你关心记忆
使用强力N 2 解决方案,因为它根本不使用额外的内存(只保留公共元素所需的内存),而N 2 在实践中对于小尺寸列表来说并不是那么糟糕。无论如何,从数据库中获取电话号码更有可能导致比N 2 算法更大的性能损失。
你关心时间,但你可以使用额外的记忆
将您的电话号码包装到包装类中,并将第一个列表中的所有电话号码添加到HashSet
。然后,遍历您的第二个列表并检查set是否包含已包装的电话号码。这将保证你有一个O(m + k * n)时间(你必须只迭代每个列表一次,而HastSet的contains方法是一个常数k - 其中k表示具有相同hashCode的字符串的平均数量。)。这倾向于O(n)因为2和k(应该是1,因为String的hashSet()碰撞非常罕见)是可以被丢弃的常数因子。
class PhoneNumber {
private final String val;
public PhoneNumber(final String val){
this.val = val;
}
@Override
public int hashCode(){
return this.getVal().hashCode();
}
@Override
public boolean equals(Object obj){
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
PhoneNumber other = (PhoneNumber )obj;
return PhoneNumberUtils.compare(this.getVal(), other.getVal()) == 0;
}
public String getVal(){
return this.val;
}
}
private Set<PhoneNumber> getCommonPhoneNumbers(List<String> dbPhoneNumbers , List<String> userPhoneNumbers){
Set<PhoneNumber> common = new HashSet<PhoneNumber>();
Set<PhoneNumber> phoneNumbers = new HashSet<PhoneNumber>();
for(String s : userPhoneNumbers){
phoneNumbers.add(new PhoneNumber(s));
}
for(String s : dbPhoneNumbers ){
PhoneNumber phoneNo = new PhoneNumber(s);
if(phoneNumbers.contains(phoneNo)){
common.add(phoneNo);
}
}
return common;
}
你关注内存和时间的复杂性。
使用基于PhoneNumberUtils.compare(String,String)
的自定义比较器对2个列表进行排序(这应该采用O(n log n)),然后一次迭代两个列表(O(min(m,n)) ):
private static final Comparator<String> phoneNoComp = new Comparator<String>(){
@Override
public int compare(final String s1, final String s2) {
return PhoneNumberUtils.compare(s1,s2);
}
};
private Set<String> getCommonPhoneNumbers(final List<String> list1 , final List<String> list2){
Set<String> common = new HashSet<String>();
Collections.sort(list1, phoneNoComp);
Collections.sort(list2, phoneNoComp);
int size1 = list1.size();
int size2 = list2.size();
int i = 0, j = 0;
while(i < size1 && j < size2){
int comparison = PhoneNumberUtils.compare(list1.get(i) , list2.get(j));
if( comparison == 0) { // found a common element.
common.add(list1.get(i));
i++;
j++;
}
else if(comparison == 1){
j++;
}
else{
i++;
}
}
return common;
}