I have an assignment to find a median in 4 individually sorted arrays.
A median is defined as the element that is in the middle of the array (at index floor(N/2))
Requirements:
- time complexity: linear to the size of the combined array
- space complexity: O(1)
I know how to find a median in 2 sorted arrays with O(1) space and O(logn) time, but I cant find a good solution for 4 arrays that meets the requirement of O(1) space.
I have tried to adjust the algorithm for 3 arrays but it didn't work very well for me.
example for my assignment:
A = {1 5 10 15 20} B = {2 3 4 6 7} C = {25 30 35 40 45} D = {8 9 90 100 145} median(A,B,C,D) = 10
Thanks in advance
Think of a single unsorted array
Consider thinking about the 4 arrays as a single unsorted array, broken into 4 parts. If you can modify the arrays, you can sort all 4 arrays as if 1 by swapping values between them (some optimizations can be made since you know the 4 arrays are sorted). Once you've sorted the arrays up to n/2 (where n is the aggregate length of the 4 arrays), just return the middle value of all 4.
Some Code
The implementation below begins to make multiple arrays function like a single one. I've implemented get
, set
, and length
methods, the basis for any array. All that needs to happen now is for the class' data to be sorted (possibly up to n/2) using get(int)
, set(int,int)
, and length()
, and a method which returns the median value median()
.
Perhaps there is a way to get the median value of an array in a single pass, I cannot think of it however. A quick sort and lookup will perform in O(nLogn) time complexity, only a single pass will reduce this to O(n) (linear to the size of the array).
There is also room for further optimization by sorting only up to n/2 within the median method, also when caching (i,j) pairs for each element when doing so.
int median( int[] a1, int[] a2, int[] a3, int[] a4 ) { MultiIntArray array = new MultiIntArray( a1, a2, a3, a4 ); array.sort(); return array.get( array.length() / 2 ); }
public class MultiIntArray { private int[][] data; public MultiIntArray( int[]... data ) { this.data = data; } public void sort() { // FOR YOU TO IMPLEMENT } public int length() { int length = 0; for ( int[] array : data ) { length += array.length; } return length; } public int get( int index ) { int i = 0; while ( index >= data[i].length ) { index -= data[i].length; i += 1; } return data[i][index]; } public void set( int index, int value ) { int i = 0; while ( index >= data[i].length ) { index -= data[i].length; i += 1; } data[i][index] = value; } }
With the restriction "time complexity is the size of the combined arrays" it is trivial, you just pick the smallest of the first elements of four arrays n/2 times. No clever algorithm needed.
I'm sure you can do it significantly faster.