-2

The programming language is C++, and the elements of the input vector are of type int and able to take all valid int values. So it’s not possible to store extra information in the input vector. Now, is it possible to sort the vector in linear time and constant extra space? Simple solutions are preferred.

And to avoid ridiculous constant factors, the constant factor in linear time is at most 100.

Zirui Wang
  • 1,028
  • 6
  • 13

3 Answers3

1

(Note: This was posted before their edit.)

Yes. Move all elements with value $-2^{31}$ to the front, order of the remaining elements doesn't matter. Easy in linear time. Then move all remaining elements with value $-2^{31}+1$ to the front (but after the $-2^{31}$ elements). Then do the same with $-2^{31}+2$, ..., $2^{31}-1$. Total time for $n$ elements is $O(2^{32}n) = O(n)$.

Kelly Bundy
  • 530
  • 2
  • 16
1

(This response was posted before their edit.)

If you require a comparison-based sorting algorithm akin to Quicksort and merge sort, the answer is no. Simply put, it can be shown that sorting an $n$-element array using a comparison-based algorithm in that respect is $\Omega(n\log n)$.

Alternatively, Kelly Bundy's solution works fine and does run in $\mathrm{O}(n)$ time, as requested. However, I would not wager too much in terms of efficiency.

-4

It’s possible, by an in-place most-significant-bit (base $2$) radix sort.

In the C++ implementation below, there are two relevant functions: sort and helper. In the main sort function, we first separate negative and non-negative numbers with a for loop and then call helper to handle each part.

helper, on the other hand, takes in a range $[a,b)$ to sort and assumes that all numbers in this range have the same bits to the left of the $e$th bit. (At the start, sort sets $e=31$ for negative numbers and $e=30$ for non-negative numbers.) So now we need to separate those numbers with $0$ at the $e$th bit and those with $1$. (For negative numbers, numbers whose absolute values have $1$ at the $e$th bit precede those with $0$.)

This is accomplished by the for loop. The loop invariant is that at the start of each iteration, the range $[a,i)$ has been processed; $[a,m)$ contains the first part (i.e., for non-negative numbers the part whose $e$th bit is $0$), and $[m,i)$ the second part. At the end of the loop we can assume that, in each of the two ranges $[a,m)$ and $[m,b)$, the numbers have the same bits to the left of $(e-1)$th bit (that is, the exponent is down by $1$), and we can further process these two ranges with recursive calls to helper.

DeepSeek-R1 mentioned in-place radix sort when I asked it this question and then I worked out the rest.

#include <bits/stdc++.h>
using namespace std;

void helper(int a, int b, int e, vector<int>& v) { if (a >= b - 1 || e < 0) return; int m = a; for (int i = a; i < b; i++) if (v[i] >= 0 && !(v[i] & 1LL << e) || v[i] < 0 && -(long long)v[i] & 1LL << e) swap(v[i], v[m++]); helper(a, m, e - 1, v); helper(m, b, e - 1, v); }

void sort(vector<int>& v) { int m = 0; for (int i = 0; i < v.size(); i++) if (v[i] < 0) swap(v[i], v[m++]); helper(0, m, 31, v); helper(m, v.size(), 30, v); }

int main() { vector<int> v = { -153423, 434, -6232323, -333222444, 23343, -743, -21, 18, 229, 2343, 0, -2147483648, -2147483647, -2147483646, 2147483647, 2147483646, 2147483645}; sort(v); for (int i : v) cout << i << " "; cout << "\n"; }

Zirui Wang
  • 1,028
  • 6
  • 13