Нули неразличимы, поэтому я предполагаю, что вам все равно, будут ли они обмениваться или даже просто перезаписываться в конце (т.е. мы просто обнуляем среднюю часть после того, как мы завершили перемещение положительных и отрицательных чисел в противоположные стороны массива).
Если вы смотрите на ситуацию, когда целые числа являются просто ключами к чему-то большему, это может быть совсем не так - вы можете захотеть сохранить нули и стабильно разбить их на части. Но если нет, вот две идеи:
Во-первых, ваша проблема идентична проблеме стабильного двоичного раздела.
Алгоритм для вашей задачи, конечно, делает стабильные двоичные разделы (просто массив без нулей). И наоборот, если в массиве есть нули, вы все равно можете использовать двоичный раздел для грязной работы: сканировать прямо через массив, меняя местами каждый ноль, с которым вы сталкиваетесь, следующим отрицательным значением (отслеживая, где это было, поэтому вы не делаете n ^ 2 всего сканирования), в результате
[смешанные -, +] [возможно, дополнительные нули] [смешанные 0, +].
Затем вы делаете два двоичных раздела, чтобы получить
[-] [+] [0] [+]
и сдвиньте значения +, чтобы получить желаемый результат.
AFAIK с двоичными разделами, вы можете выбрать любые два стабильных, на месте и O (n). Так что, похоже, вам не повезло, но очевидно, что алгоритм O (n * log n) на месте известен как алгоритм O (n), использующий пустое пространство log (n).
Во-вторых, если вы можете гарантировать, что число нулей будет не менее f (n), нули могут компенсировать недостаток царапин; просто получить стабильный раздел на месте за время O (n ^ 2 / f (n)). В частности, если нули будут хотя бы некоторой постоянной долей массива, вы получите O (n) времени выполнения, просто выполнив эти два шага, пока не закончите:
- Сканирование прямо через массив, заменяя каждый ноль, с которым вы сталкиваетесь, следующим отрицательным значением
- Сканирование влево через массив, меняя местами каждый ноль со следующим положительным значением
Если нули столь же многочисленны, как и любой другой тип, это делается после выполнения 1, затем 2, затем 1.