我们有列表,如果整数(或其他一些对象),如:
[0, 0, 1, 1, ... , 777777, ... , 999999, 999999]
Java代码:
List<Integer> ints = new LinkedList<Integer>();
for (int i = 0; i < 999999; i++) {
ints.add(i); // add first value
if (i!=777777){
ints.add(i); // add duplicate value in not '5'
}
}
我以这种方式解决了这个问题:
Integer unique = null;
while (true) {
unique = ints.get(0);
ints.remove(0);
if (ints.contains(unique)) {
ints.remove(ints.indexOf(unique));
} else {
break;
}
}
System.out.println(unique);// 777777
大约需要30毫秒。使用ArrayList,它的工作时间更长。 问题是如何以最佳(正确/优雅/最快)方式从此列表中获取一个唯一值(例如777777)。
答案 0 :(得分:3)
由于您在循环中运行ints.contains(unique)
和ints.indexOf(unique)
等线性时间操作,因此您的实现效率非常低。因此,在最糟糕的情况下,您的运行时间为O(n^2)
。
如果数字总是排序的(就像在你的例子中那样),你可以在列表的元素上迭代一次,找到不等于list.get(i)
和{{list.get(i-1)
的元素list.get(i+1)
1}}。这将采用O(n)
。
如果数字并不总是排序,您可以在O(nlogn)
中对它们进行排序,然后像以前一样继续。
或者您可以迭代数字一次,计算每个数字的出现次数(您可以将计数存储在HashMap
中),并找到计数为1的数字。这将需要{{1无论输入列表是否已排序。
答案 1 :(得分:1)
您使用的是错误的收藏品。列表不是此问题中的正确集合。
您应该使用 HashSet 来解决此问题。
private void find(List<Integer> ints){
HashSet<Integer> set = new HashSet<>();
for(int i=0;i<ints.size();i++){
if(set.contains(i)){
set.remove(i);
}else{
set.add(i);
}
}
Iterator<Integer> itr = set.iterator();
if(itr.hasNext()){
System.out.println("Unique value is :"+itr.next());
}else{
System.out.println("There is no duplicated value");
}
}
此方法仅适用于2个和1个计数列表项。如果您有相同的数字3次,这种方法会发现它是重复的。
排序可能是答案,但排序最多只有O(logn),在O(n)之后找到重复的元素。如果您可以在创建列表时创建哈希集,则此方法会将重复的元素查找为O(1)。
答案 2 :(得分:1)
首先获取唯一元素,然后使用集合api的频率方法来获取重复项
Set<String> uniqueSet = new HashSet<String>(list);
for (String temp : uniqueSet) {
if(Collections.frequency(list, temp)==1) {
System.out.println(temp);
}
}
这将从列表中返回唯一元素。
答案 3 :(得分:0)
如下所示尝试jdk8的流媒体API如何:
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FiindUnique {
public static void main(String[] args) {
System.out.println("Hello World");
Collection<String> list = Arrays.asList("A", "B", "C", "D", "A", "B", "C");
//solution 1
List<String> distinctElements = list.stream().filter(name -> Collections.frequency(list, name) == 1).collect(Collectors.toList());
System.out.println(distinctElements);
//Solution 2
List<String> distinctElements2 = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(e -> e.getValue() == 1)
.map(e -> e.getKey())
.collect(Collectors.toList());
System.out.println(distinctElements2);
}
}
答案 4 :(得分:0)
除了其他答案给出的Set
解决方案之外,如果您知道重复元素仅出现两次(或偶数次)并且只有一个不重复的数字,您可以对所有值进行异或运算,以找到唯一的数字。
public int findUnique(int[] nums) { // Or (List<Integer> nums), it works also
int xor = 0;
for(int i : nums){
xor ^= i;
}
return xor;
}
此解决方案比其他解决方案更快,更短。
您也可以采用Java 8样式进行此操作,但是它当然会变慢:
public int findUnique(int[] nums) {
return Arrays.stream(nums)
.reduce((acc,i) -> acc ^= i)
.orElseThrow(IllegalArgumentException::new);
}
答案 5 :(得分:0)
通过二分查找找到反转点,即唯一数偶数和奇数索引前的数相同,唯一数后奇数和偶数的数相同,所以我们可以进行二分查找找到反演点的时间复杂度将为 log(N)
答案 6 :(得分:-1)
您认为数组已排序吗? 这应该更快。
HashSet<Integer> s = new HashSet<Integer>();
for ( Integer i : ints){
if ( s.contains(i)){
s.remove(i); // remove dups
}
else{
s.add(i); //add uniques
}
}
for ( Integer unique: s){
// should contain one value
System.out.println(unique);// 777777
}