Я придумал несколько решений, лучшее из которых - вывести строку - модификацию вашего исходного поста.
Это решение будет соответствовать алгоритмическому времени использования StringBuilder (l.size * 2 -1). * 2 - 1
- для запятых.
Следующее решение уменьшает внутренний цикл до O (1), предварительно выделяя список массивов с максимальным количеством элементов, каждый из которых может быть назначен напрямую. Вашему исходному коду требовалась глубокая копия всех элементов массива, в результате чего время O (N) добавляло новый элемент, превышающий начальную емкость массива. Следующий код инициализирует список массивов до нужного размера.
Вся сложность составляет 1/2 * N + (1/2 * (N - 1) + (1/4 * (N - 2)) + (1/8 * (N -3)) ... ) * +1010 *
Моя математика / анализ могут быть неверными, однако нижняя граница задана тем, что для конкатенации строк всех элементов массива требуется как минимум N операций => O (N)
Верхняя граница, при условии, что моя математика верна выше, также равна O (N). Поскольку все, что меньше половины значения, не может быть добавлено к значению, чтобы итоговое значение превысило исходное значение.
Если моя математика неверна, наихудшим случаем является N log N.
Абсолютная верхняя граница равна N в квадрате (если вы игнорируете факт, N уменьшается при каждой итерации).
List<String> l = new ArrayList<>();
// some code to add N items to l
//.
//.
//.
while (l.size() > 1) {
int lo = 0, hi = l.size() - 1;
List<String> temp = new ArrayList<>(l.size/2 + 1);
while (lo < hi) {
temp.add("(" + l.get(lo) + "," + l.get(hi) + ")");
lo++;
hi--;
}
l = temp;
}
На практике ограничивающим фактором алгоритма становится выделение и перераспределение памяти в 1/2 N списков массивов для всех значений N, кроме малых и средних,