[英]Java - Find the difference between two arrays with duplicates
我已经实现了一种查找两个未排序数组之间差异的方法。 目前我已经实现了没有重复的差异。 但是如何让它也考虑重复项呢?
例如,对于下面的输入数组,我期望输出[4 5 3]
:
int[] arr1 = {1, 2, 3, 4, 5, 5};
int[] arr2 = {1, 2, 3, 5, 3};
对于这些输入数组,我期望[7 7 9]
int[] arr3 = {7, 7, 4, 9, 6};
int[] arr4 = {4, 6};
//
static ArrayList<Integer> findDifference(int[] a, int[] b) {
ArrayList<Integer> arr1 = new ArrayList<Integer>() {
{ for (int i : a) add(i); }
};
ArrayList<Integer> arr2 = new ArrayList<Integer>() {
{ for (int i : b) add(i); }
};
if (arr1.size() > arr2.size()) {
arr1.removeAll(arr2);
return arr1;
} else {
arr2.removeAll(arr1);
return arr2;
}
}
您可以为第一个数组中的每个值保留一个计数。 您可以使用HashMap
来保存特定值出现的次数。
然后,对于第二个数组中的每个value
,您可以减少该value
的已计算计数。 最后,如果特定值的计数为0
,则这意味着两个数组中出现的次数相同。 否则,其中一个数组包含多次出现的value
。 特定value
的差异数将是abs(count[value])
(因为在第二个数组包含的value
比第一个数组出现次数更多的情况下,它可能会变成负数)。
此 Java 代码说明了该方法:
public List<Integer> findDiff(int[] first, int[] second) {
Map<Integer, Integer> count = new HashMap<>();
for (int value : first) {
int current = count.getOrDefault(value, 0);
count.put(value, current + 1);
}
for (int value : second) {
int current = count.getOrDefault(value, 0);
count.put(value, current - 1);
}
List<Integer> result = new ArrayList<>();
for (Map.Entry<Integer, Integer> entry : count.getEntrySet()) {
int diff = entry.getValue();
int times = Math.abs(diff);
for (int i = 0; i < times; i++) {
result.add(entry.getKey());
}
}
return result;
}
显然,时间和内存的复杂度都是线性的。
几乎肯定不是最佳解决方案,但作为您可以使用的东西:
private static <X> Collection<X> findDiff(final Collection<X> a, final Collection<X> b) {
// Copy the Collections so you don't modify inputs
// and so you can safely 'remove' from them.
final List<X> aCopy = new ArrayList<>(a);
final List<X> bCopy = new ArrayList<>(b);
// Remove all common elements from the copies
// Using 'removeAll' will pull out duplicates,
// so do this one-by-one.
for (final X bElement : b) {
aCopy.remove(bElement);
}
// Note it's important to iterate over 'a' here, not
// aCopy since the elements of aCopy (may) have had some
// entries 'remove'd.
for (final X aElement : a) {
bCopy.remove(aElement);
}
// Combine the two cleared out lists to find
// the cumulative difference.
final List<X> diff = new ArrayList<>(aCopy);
diff.addAll(bCopy);
return Collections.unmodifiableCollection(diff);
}
请注意,您可以使用如下简单的方法将int[]
转换为Collection<Integer>
:
IntStream.of(arr).boxed().collect(Collectors.toList());
另请注意:您可以使用较少的中间Collection
来完成此操作。 如果您不介意修改输入,则只需复制其中一个输入。 而且您不需要将两者组合成一个新的diff
。 这只是可以使用的东西(并且更具解释性)。
如果您想要两个数组之间的绝对差异(在本例中唯一不同的元素是4
),您可以计算两个集合的并集和交集。
要排除重复项,您还可以使用Set
而不是List
来保证唯一性。 一个非常简单的示例可能如下所示:
public static void main(String... args) {
Integer[] arr1 = {1, 2, 3, 4, 5, 5};
Integer[] arr2 = {1, 2, 3, 5, 3};
Set<Integer> diffs = findDiff(arr1, arr2);
diffs.forEach(System.out::println);
}
public static Set<Integer> findDiff(Integer[] array1, Integer[] array2) {
List<Integer> list1 = Arrays.asList(array1);
List<Integer> list2 = Arrays.asList(array2);
Set<Integer> union = new HashSet<>(list1);
union.addAll(list2);
Set<Integer> intersection = new HashSet<>(list1);
intersection.retainAll(list2);
union.removeAll(intersection);
return union;
}
这是一个适用于这两个示例的解决方案:
public static void main(String[] args) {
int[] arr1 = {1, 2, 3, 4, 5, 5};
int[] arr2 = {1, 2, 3, 5, 3};
System.out.println(findDifference(arr1, arr2));
int[] arr3 = {7, 7, 4, 9, 6};
int[] arr4 = {4, 6};
System.out.println(findDifference(arr3, arr4));
}
static ArrayList<Integer> findDifference(int[] a, int[] b) {
ArrayList<Integer> list1 = new ArrayList<Integer>();
Arrays.stream(a).forEach(e -> list1.add(e));
ArrayList<Integer> list2 = new ArrayList<Integer>();
Arrays.stream(b).forEach(e -> list2.add(e));
ArrayList<Integer> list1Copy = new ArrayList<Integer>();
ArrayList<Integer> list2Copy = new ArrayList<Integer>();
list1Copy.addAll(list1);
list2Copy.addAll(list2);
list1.forEach(e -> list2Copy.remove(e));
list2.forEach(e -> list1Copy.remove(e));
list1Copy.addAll(list2Copy);
return list1Copy;
}
输出:
[4, 5, 3] [7, 7, 9]
原理是在副本上处理删除操作,以便能够在初始列表上再次迭代
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.