У меня есть простая проблема, чтобы найти первый уникальный элемент в массиве А. Но меня беспокоит сложность времени с использованием разных методов. Я пробовал эти два метода до сих пор.LinkedHashMap сложность
Первый способ:
LinkedHashMap<Integer, List<Integer>> map = new LinkedHashMap<Integer, List<Integer>>();
for (int i = 0; i < A.length; i++)
{
if (!map.containsKey(A[i]))
map.put(A[i], new ArrayList<>());
map.get(A[i]).add(i);
}
for (Map.Entry<Integer, List<Integer>> m : map.entrySet())
if (m.getValue().size() == 1)
return m.getKey();
return -1;
Второй метод:
for(int i=0; i< A.length; i++){
boolean unique = true;
nestedFor:for(int j=0; j< A.length; j++){
if(i != j && A[i] == A[j]){
unique = false;
break nestedFor;
}
}
if(unique)
return A[i];
}
return -1;
Тестирование с массивом элементов 1000000, первый метод выполняет на ~ 2000 мс, а второй при ~ 10ms. Мой вопрос: не должен ли первый метод выполняться быстрее, так как его сложность O (nLogn) по сравнению со вторым методом, сложность которого равна O (n^2)? Что мне здесь не хватает? Ниже тестовый код:
int[] n = new int[1000000];
for (int i = 0; i < n.length; i++)
n[i] = new Random().nextInt(2000000);
long start = System.currentTimeMillis();
firstUnique(n);
System.err.println("Finished at: " + (System.currentTimeMillis() - start) + "ms");
EDIT:
for (int i = 0; i < A.length; i++)
{
if (!map.containsKey(A[i]))
map.put(A[i], new ArrayList<>());
map.get(A[i]).add(i);
}
Потребляет 99% времени выполнения, в то время как
for (Map.Entry<Integer, List<Integer>> m : map.entrySet())
if (m.getValue().size() == 1)
return m.getKey();
всегда 1-3ms. Итак, да, заполнение карты является самой дорогой операцией.
Что вы предложите как наиболее эффективный метод для такого рода проблем?
с помощью первого метода вы также измеряете создание не менее 2 миллионов объектов, которые выходят за пределы области действия в конце вызова функции, однако ваш GC обрабатывает это , если 'A' во второй версии является' int [] ', тогда у вас нет этих накладных расходов ... – BeyelerStudios
Использование System.currentTimeMillis() не является хорошим способом выполнения теста, см. http: // stackoverflow. com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java для получения дополнительной информации о выполнении теста Java – CConard96
Вы можете сделать второй метод примерно в два раза быстрее (в худшем случае) путем итерации 'for (int j = i + 1; ...)'. Вы не только повторяете половину элементов, но также пропускаете проверку 'i! = J'. –