How can I do arrangements. of numbers... such that each new number formed out of arrangement has at max a difference of 1 from prev maxima.
e.g.
if input is k=1 output will be 1
if k =2 outputs are : 11, 12
2,1 is wrong as left most has to be 1 always.
if k = 3 outputs are: 111,112, 121, 122, 123
if k = 4 : 1111,1112,1121,1122,1123,1212,1211,1213,1223,1221, 1222, 1233, 1234
1423 is wrong diff b/w 1 and 4 is 3.
1243 is wrong diff b/w 2 and 4 is 2....
How I do this using DP, if possible?
This is one of the solution for above question... can anyone help me to understand this code...
Thanks in advance...
public class MaxOneDiff {
public static void main(String[] args) {
int k = 4;
getList(k);
}
public static void getList(int k) {
int arr[] = new int[k];
int index = 0;
printRecList(k, arr, index, k);
}
public static void printRecList(int k, int arr[], int index, int range) {
if (k == 0) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
System.out.println();
} else {
for (int i = 1; i <= range; i++) {
if (index == 0) {
arr[index] = i;
printRecList(k - 1, arr, index + 1, range);
} else {
int t = arr[index-1]-i;
t = t > 0 ? t : -t;
if (t < 2) {
arr[index] = i;
printRecList(k - 1, arr, index + 1, range);
}
}
}
}
}
}
Let's start with the easy part:
public static void getList(int k) {
int arr[] = new int[k];
int index = 0;
printRecList(k, arr, index, k);
}
This is a helper to the Print Recursive List function, just setting up the initial stuff.
public static void printRecList(int k, int arr[], int index, int range) {
This is a recursive function, it should (and does) contain two main parts:
A base case (here, when k==0 )
A non-base case which does something, reducing the problem into smaller problem(s), and recurses.
Base case:
if (k == 0) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
System.out.println();
If k==0, print out the numbers in the array from left to right, then put a new-line at the end.
Non-Base Case: (the more complicated part)
else {
for (int i = 1; i <= range; i++) {
if (index == 0) {
arr[index] = i;
printRecList(k - 1, arr, index + 1, range);
} else {
int t = arr[index-1]-i;
t = t > 0 ? t : -t;
if (t < 2) {
arr[index] = i;
printRecList(k - 1, arr, index + 1, range);
}
}
}
}
'i' goes from 1 to range,
The helper function calls this with index=0, so the first/top level of recursion, is composed of setting the first element (element 0) of the array to i, and calling the recursive method.
Never again will index == 0 in the recursive calls, so we turn our attention to the else clause.
Here we want to know if we can assign the value i to the next element over, so we check to see if the absolute value of elementToLeft minus i is greater than or equal to 2.
If 'i' is valid to assign in that position (i.e. it is only 1 or 0 different from the value to the left, and 'i' can only get as high as range from the for loop.)
Then we assign it, and check the next position over.
This ends when we have reached the last element in the array.
Related
I am currently in my first year of university and my teacher gave us an interesting problem
Given the 2 dimensional array m (the column length is equal to the row length for example 4x4, 3x3)
We know that if m goes through the function test it will return true
Now we need to write a function that based on that information will find the given value in m and return false or true if was found. In addition, the function must be with time complexity of O(n) or less when n is the length of row/column (For example if the matrix is 5x5 then n is 5). The function cannot use recursion
Here is function test:
public static boolean test(int [][] m)
{
int n=m.length;
for(int r=0; r<(n-1); r++)
for (int c=0; c<n; c++)
for (int i=0; i<n; i++)
if(m[r][c] > m[r+1][i]) return false;
return true;
}
Here is an example for a matrix that I came up with that returns true:
1, 3, 2, 5
10, 9, 7, 15
17, 25, 16, 20
50, 30, 28, 40
Here is a possible function signature:
public static boolean findValTest (int [][] m, int val)
Thanks for everyone who answers!
Update: Here's an O(nlogn) solution, we need further discussion to find a number in one column in O(1).
public static boolean findValTest(int[][] m, int val) {
for (int c = 0; c < m.length; c++) {
if (val < m[c][0] || val > m[c][m[c].length - 1]) continue;
if (binarySearch(m, c, val)) return true;
}
return false;
}
private static boolean binarySearch(int[][] m, int col, int key) {
int low = 0, high = m[col].length - 1;
while (low <= high) {
int mid = low + ((high - low) / 2);
if (m[mid][col] < key) {
low = mid + 1;
} else if (m[mid][col] > key) {
high = mid - 1;
} else if (m[mid][col] == key) {
return true;
}
}
return false;
}
I have managed to figure it out. It is basically O(3n) but since 3 is constant it is O(n).
Basically we use the first column to give us the index of two rows where the value might be in.
For example if we use the matrix we I gave as an example and the value is 16 we go like this:
Is val between 1 and 10? No.
Is val between 10 and 17? Yes
Search second row and third row.
Here is the code(It is kinda long and ugly but hopefully you will understand it):
// We search in the first column between what two numbers the value is,
// Then we search for row of the first index, if not there we search the row of the other index
// Time Complexity: O(n). We go through the first column which is O(n) and then we go over 2 rows which is O(2n). Together its O(3n) but because 3 is constant the time is O(n)
public static boolean findValTest(int[][] m, int val) {
int[] index = whichRows(m,val);
if(index[0] == -1 && index[1] == -1) // Indicator that the number was found in the first column
return true;
if(index[1] == -1){
// We search in only one row
for(int i = 0; i < m.length - 1; i++){
if(val == m[index[0]][i]) {
return true;
}
}
}
else {
// Search both given rows by index
for(int i = 0; i < index.length; i++){
for(int j = 0; j < m.length; j++) {
if(val == m[index[i]][j])
return true;
}
}
}
return false;
}
public static int[] whichRows(int[][] m, int val) {
int[] index = {0,0}; int len = m.length;
// -1 in the index indicates that only one row needs to be searched, or the first or the last
if(m[len-1][0] < val) // Only the last row(Which contains the biggest numbers in the matrix) needs to be searched
{
index[0] = len-1; index[1] = -1;
}
else if(m[0][0] > val){ // Only the first row needs to be searched
index[0] = 0; index[1] = -1;
}
else { // We search between
for(int i = 0; i < len - 1; i++){
if(m[0][i] == val)
{
index[0] = -1; index[1] = -1;
return index;
}
if(m[i][0] < val && val < m[i+1][0]){
index[0] = i; index[1] = i +1;
break;
}
}
}
return index;
}
just wanted to update you that your code doesn't work at certain times.
Wanted to give you a breakdown but unfortunately something came up and I will have to go for the next couple of days, so it is my hope that you fix whatever's plaguing your design.
Try to test it with other numbers and see for yourself.
I tested it with the following matrix:
int[][] matrix = {
{13, 2, 17, 29},
{52, 54, 62, 73},
{140, 120, 111, 100},
{235, 245, 255, 265},
};
and used 265 and 235 as inputs, to which the output was false.
Good luck :)
I have made this code to rotate an array by k times. In this when I'm adding i=0 , it is showing an "ArrayOutOfBounds" exception, and when I'm changing the value of i by 1, it is showing wrong output. Why is it showing this exception? And is there any way I could correct this code?
public void rotate(int[] nums, int k)
{ int j=0, temp=0;
for(j=0;j<k;j++)
{
for(int i=0;i<nums.length;i++)
{
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
}
}
At i=0 you are trying to access nums[i-1] = num[-1] which is an invalid position and hence an ArrayOutOfBound exception is thrown.
So, the modified version would be:
for (j=0; j<k; j++)
{
for (int i=1;i<nums.length;i++)
{
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
But the above will rotate the array by k times towards the left not right as you are shifting the elements towards the left. So, to get the right rotation you need to shift the elements from the end of the array. Like:
for (j=0; j<k; j++)
{
for (int i=nums.length-1; 0<i; i--)
{
// shifting towards the right
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
Edit (from comments above): If i is 0, you're trying to get an index of -1 which will raise an ArrayOutOfBounds exception. If i starts from 1, then you're not dealing with the first number.
Here's the function you can use to rotate integers to the right:
public void rotate(int[] nums, int k) {
int arrLen = nums.length;
// If the number of times you want to rotate is bigger than the size of the array, get the minimum number of rotations to get the same result.
while (k > n) {
k = k - arrLen;
}
k = arrLen - k;
k = k % arrLen;
int i, m, n, temp;
int g_c_d = gcd(k, arrLen);
// Move the value in the i-th index
for (i = 0; i < g_c_d; i++) {
temp = arr[i];
m = i;
while (true) {
n = m + k;
if (n >= arrLen) {
n = n - arrLen;
}
if (n == i) {
break;
}
arr[m] = arr[n];
m = n;
}
arr[m] = temp;
}
}
// Find the greatest common divisor of two numbers, a and b
public void gcd(int a, int b) {
if (b == 0) {
return a;
} else {
return gcd(b, a % b);
}
}
Let me briefly explain what it does. This is one of the most known algorithms: juggling. You divide the array into the n number of sets where n denotes the greatest common divisor of the length of the array and the number of times you want to rotate. Then, you move the numbers within sets.
This might be the most efficient in terms of time (as its time complexity is O(n)).
A better solution would be taking a copy of the given array with the values '0' then looping through the given array to obtain a new_index.
Formula for the New_index for the Clock-wise rotating array:
for(int i=0;i<nums.length;i++){
int new_index = (old_index+k)%(a.length)
copy[new_index] = a[old_index]
}
Now the entire function code would be:
public static void rotate(int[] a, int k)
{
int n = a.length;
int[] copy = new int[n];
// fill the values with zeroes
for(int i=0;i<n;i++){
copy[i]=0;
}
// rotate the array
for(int i=0;i<n;i++){
int new_index = (i+k)%n;
copy[new_index] = a[i];
}
// Now that the array is copied, copy the elements to the original array. Because they asked to rotate the given array.
for(int i=0;i<n;i++){
a[i]=copy[i];
}
}
function solution(arr, k) {
if(k == 0) return arr;
if(arr.length == k) return arr;
if(arr !== undefined && arr !== null){
let counter = k > arr.length ? k % arr.length : k;
let rotArray = [];
rotArray = arr.slice(arr.length - counter, arr.length).concat(arr.slice(0,arr.length - counter))
return rotArray;
}
return arr;
}
public static int[] sortArray(int[] arr) {
Arrays.sort(arr);
return arr;
}
public static int findElement(int[] arr, int x) {
int start = 0;
int end = arr.length;
int mid = 0;
while (start <= end) {
mid = (start + end)/2;
if (arr[mid] == x) {
return x;
}
else if (x <= arr[mid]) {
end = mid - 1;
}
else {
start = mid + 1;
}
}
return mid;
}
public static void printKclosest(int arr[], int x, int k)
{
int element = findElement(arr, x);
int count = 0;
for (int i = 0; i < arr.length; i++) {
int difference = Math.abs(arr[i] - element);
while (count < k) {
if (difference > 0) {
System.out.println(arr[i]);
count++;
}
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
int[] array = {-1, 3, 5, 2, 1, 7};
sortArray(array);
System.out.println(Arrays.toString(array));
printKclosest(array, 2, 3);
}
}
for find the k nearest elements, i was thinking I could use a for loop to go through each element in the array and subtract from the element that's X and print the number of k elements that have the smallest difference, but the output I'm getting is -1 k amount of times.
function findElement returns x value if x exists but index of potential place for x if it does not present in array.
So in the second case your comparison int difference = Math.abs(arr[i] - element); has no sense
How to overcome: change in findElement
int end = arr.length - 1;
return x;
to
return mid;
and
difference = Math.abs(arr[i] - arr[element]);
But approach to get k closest numbers is completely wrong. Suggestion:
Set L index to element and R index to element+1
Compare abs differences for L and R. Output smaller. If smaller is for R, decrement L, otherwise increment R. Repeat k times (don't forget about array range)
In addition to MBo's great suggestion for outputting the k closest elements using L and R pointers, you could also solve this without sorting the array in O(n log k) time by iterating over the array once and keeping the chosen elements in a heap, each time removing the farthest (k+1)th element.
I have the following problem:
You are given N counters, initially set to 0, and you have two possible operations on them:
increase(X) − counter X is increased by 1,
max counter − all counters are set to the maximum value of any counter.
A non-empty zero-indexed array A of M integers is given. This array represents consecutive operations:
if A[K] = X, such that 1 ≤ X ≤ N, then operation K is increase(X),
if A[K] = N + 1 then operation K is max counter.
For example, given integer N = 5 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the values of the counters after each consecutive operation will be:
(0, 0, 1, 0, 0)
(0, 0, 1, 1, 0)
(0, 0, 1, 2, 0)
(2, 2, 2, 2, 2)
(3, 2, 2, 2, 2)
(3, 2, 2, 3, 2)
(3, 2, 2, 4, 2)
The goal is to calculate the value of every counter after all operations.
Write a function:
class Solution { public int[] solution(int N, int[] A); }
that, given an integer N and a non-empty zero-indexed array A consisting of M integers, returns a sequence of integers representing the values of the counters.
For example, given:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the function should return [3, 2, 2, 4, 2], as explained above.
Assume that:
N and M are integers within the range [1..100,000];
each element of array A is an integer within the range [1..N + 1].
Complexity:
expected worst-case time complexity is O(N+M);
expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
I have answered this problem using the following code, but only got 80% as opposed to 100% performance, despite having O(N+M) time complexity:
public class Solution {
public int[] solution(int N, int[] A) {
int highestCounter = N;
int minimumValue = 0;
int lastMinimumValue = 0;
int [] answer = new int[N];
for (int i = 0; i < A.length; i++) {
int currentCounter = A[i];
int answerEquivalent = currentCounter -1;
if(currentCounter >0 && currentCounter<=highestCounter){
answer[answerEquivalent] = answer[answerEquivalent]+1;
if(answer[answerEquivalent] > minimumValue){
minimumValue = answer[answerEquivalent];
}
}
if (currentCounter == highestCounter +1 && lastMinimumValue!=minimumValue){
lastMinimumValue = minimumValue;
Arrays.fill(answer, minimumValue);
}
}
return answer;
}
}
Where is my performance here suffering? The code gives the right answer, but does not perform up-to-spec despite having the right time complexity.
Instead of calling Arrays.fill(answer, minimumValue); whenever you encounter a "max counter" operation, which takes O(N), you should keep track of the last max value that was assigned due to "max counter" operation, and update the entire array just one time, after all the operations are processed. This would take O(N+M).
I changed the variables names from min to max to make it less confusing.
public class Solution {
public int[] solution(int N, int[] A) {
int highestCounter = N;
int maxValue = 0;
int lastMaxValue = 0;
int [] answer = new int[N];
for (int i = 0; i < A.length; i++) {
int currentCounter = A[i];
int answerEquivalent = currentCounter -1;
if(currentCounter >0 && currentCounter<=highestCounter){
if (answer[answerEquivalent] < lastMaxValue)
answer[answerEquivalent] = lastMaxValue +1;
else
answer[answerEquivalent] = answer[answerEquivalent]+1;
if(answer[answerEquivalent] > maxValue){
maxValue = answer[answerEquivalent];
}
}
if (currentCounter == highestCounter +1){
lastMaxValue = maxValue;
}
}
// update all the counters smaller than lastMaxValue
for (int i = 0; i < answer.length; i++) {
if (answer[i] < lastMaxValue)
answer[i] = lastMaxValue;
}
return answer;
}
}
The following operation is O(n) time:
Arrays.fill(answer, minimumValue);
Now, if you are given a test case where the max counter operation is repeated often (say n/3 of the total operations) - you got yourself an O(n*m) algorithm (worst case analysis), and NOT O(n+m).
You can optimize it to be done in O(n+m) time, by using an algorithm that initializes an array in O(1) every time this operation happens.
This will reduce worst case time complexity from O(n*m) to O(n+m)1
(1)Theoretically, using the same idea, it can even be done in O(m) - regardless of the size of the number of counters, but the first allocation of the arrays takes O(n) time in java
This is a bit like #Eran's solution but encapsulates the functionality in an object. Essentially - keep track of a max value and an atLeast value and let the object's functionality do the rest.
private static class MaxCounter {
// Current set of values.
final int[] a;
// Keeps track of the current max value.
int currentMax = 0;
// Min value. If a[i] < atLeast the a[i] should appear as atLeast.
int atLeast = 0;
public MaxCounter(int n) {
this.a = new int[n];
}
// Perform the defined op.
public void op(int k) {
// Values are one-based.
k -= 1;
if (k < a.length) {
// Increment.
inc(k);
} else {
// Set max
max(k);
}
}
// Increment.
private void inc(int k) {
// Get new value.
int v = get(k) + 1;
// Keep track of current max.
if (v > currentMax) {
currentMax = v;
}
// Set new value.
a[k] = v;
}
private int get(int k) {
// Returns eithe a[k] or atLeast.
int v = a[k];
return v < atLeast ? atLeast : v;
}
private void max(int k) {
// Record new max.
atLeast = currentMax;
}
public int[] solution() {
// Give them the solution.
int[] solution = new int[a.length];
for (int i = 0; i < a.length; i++) {
solution[i] = get(i);
}
return solution;
}
#Override
public String toString() {
StringBuilder s = new StringBuilder("[");
for (int i = 0; i < a.length; i++) {
s.append(get(i));
if (i < a.length - 1) {
s.append(",");
}
}
return s.append("]").toString();
}
}
public void test() {
System.out.println("Hello");
int[] p = new int[]{3, 4, 4, 6, 1, 4, 4};
MaxCounter mc = new MaxCounter(5);
for (int i = 0; i < p.length; i++) {
mc.op(p[i]);
System.out.println(mc);
}
int[] mine = mc.solution();
System.out.println("Solution = " + Arrays.toString(mine));
}
My solution: 100\100
class Solution
{
public int maxCounterValue;
public int[] Counters;
public void Increase(int position)
{
position = position - 1;
Counters[position]++;
if (Counters[position] > maxCounterValue)
maxCounterValue = Counters[position];
}
public void SetMaxCounter()
{
for (int i = 0; i < Counters.Length; i++)
{
Counters[i] = maxCounterValue;
}
}
public int[] solution(int N, int[] A)
{
if (N < 1 || N > 100000) return null;
if (A.Length < 1) return null;
int nlusOne = N + 1;
Counters = new int[N];
int x;
for (int i = 0; i < A.Length; i++)
{
x = A[i];
if (x > 0 && x <= N)
{
Increase(x);
}
if (x == nlusOne && maxCounterValue > 0) // this used for all maxCounter values in array. Reduces addition loops
SetMaxCounter();
if (x > nlusOne)
return null;
}
return Counters;
}
}
( #molbdnilo : +1 !) As this is just an algorithm test, there's no sense getting too wordy about variables. "answerEquivalent" for a zero-based array index adjustment? Gimme a break ! Just answer[A[i] - 1] will do.
Test says to assume A values always lie between 1 and N+1. So checking for this is not needed.
fillArray(.) is an O(N) process which is within an O(M) process. This makes the whole code into an O(M*N) process when the max complexity desired is O(M+N).
The only way to achieve this is to only carry forward the current max value of the counters. This allows you to always save the correct max counter value when A[i] is N+1. The latter value is a sort of baseline value for all increments afterwards. After all A values are actioned, those counters which were never incremented via array entries can then be brought up to the all-counters baseline via a second for loop of complexity O(N).
Look at Eran's solution.
This is how we can eliminate O(N*M) complexity.
In this solutions, instead of populating result array for every A[K]=N+1, I tried to keep what is min value of all elements, and update result array once all operation has been completed.
If there is increase operation then updating that position :
if (counter[x - 1] < minVal) {
counter[x - 1] = minVal + 1;
} else {
counter[x - 1]++;
}
And keep track of minVal for each element of result array.
Here is complete solution:
public int[] solution(int N, int[] A) {
int minVal = -1;
int maxCount = -1;
int[] counter = new int[N];
for (int i = 0; i < A.length; i++) {
int x = A[i];
if (x > 0 && x <= N) {
if (counter[x - 1] < minVal) {
counter[x - 1] = minVal + 1;
} else {
counter[x - 1]++;
}
if (maxCount < counter[x - 1]) {
maxCount = counter[x - 1];
}
}
if (x == N + 1 && maxCount > 0) {
minVal = maxCount;
}
}
for (int i = 0; i < counter.length; i++) {
if (counter[i] < minVal) {
counter[i] = minVal;
}
}
return counter;
}
This is my swift 3 solution (100/100)
public func solution(_ N : Int, _ A : inout [Int]) -> [Int] {
var counters = Array(repeating: 0, count: N)
var _max = 0
var _min = 0
for i in A {
if counters.count >= i {
let temp = max(counters[i-1] + 1, _min + 1)
_max = max(temp, _max)
counters[i-1] = temp
} else {
_min = _max
}
}
return counters.map { max($0, _min) }
}
If an array contains 1,7,7,3,6 and if user asks what 2nd largest element is the output should be 7(not 6) since duplicate values are treated as distinct.
This is my code.
I am using Deterministic search to find the suitable pivot .
Its complexity is O(n).
I am stuck at the error generated by my code .
Please do help me.
import java.util.Random;
import java.util.Scanner;
public class deven {
public static void main(String args[]){
Scanner in=new Scanner(System.in);
int len=in.nextInt();
int n=in.nextInt();
int array[]=new int[len];
for (int i = 0; i < len; i++) {
array[i]=in.nextInt();
}
System.out.println(select(array,len,n));
}
static int below[];
static int above[];
static int pivot;
static int i;
static int j;
static int x;
static int y;
static int index;
static Random rand=new Random();
static int select(int array[],int len,int n){
if(len==1)
return array[0];
pivot=pivot(array, len);
below=new int[len];
above=new int[len];
//System.out.println("Block");
x=0;
y=0;
int temp=0;
for(i=0;i<len;i++){
if(array[i]>pivot){
below[x++]=array[i];
}
else if(array[i]<pivot){
above[y++]=array[i];
}
else {
if(temp!=0){
below[x++]=array[i];
}
temp=1;
}
}
i = x;
j = len - y;
if(n<i) return select(below,x,n);
else if(n>=j) return(select(above,y,n-j));
else return(pivot);
}
static int pivot(int array[],int len){
if(len==1){
return array[0];
}
int numOfGroups=len/5;
if(len%5!=0){
numOfGroups++;
}
int setOfMedians[]=new int[numOfGroups];
for (int i = 0 ; i < numOfGroups ; i++)
{
int[] subset;
if(array.length % 5 > 0)
{
if (i == numOfGroups - 1)
{
subset = new int[array.length % 5];
}
else
{
subset = new int[5];
}
}
else
{
subset = new int[5];
}
for (int j = 0; j < subset.length ; j++)
{
subset[j] = array[5*i+j];
}
setOfMedians[i] = median(subset);
}
int goodpivot=select(setOfMedians, numOfGroups,numOfGroups/2 );
return goodpivot;
}
static int median(int[] array)
{
if (array.length == 1)
{
return array[0];
}
int smallerCount = 0;
for (int i = 0 ; i < array.length ; i++)
{
for (int j = 0 ; j < array.length ; j++)
{
if (array[i] < array[j])
{
smallerCount++;
}
}
if (smallerCount == (array.length - 1)/2)
{
return array[i];
}
smallerCount = 0;
}
return -1;
}
}
Input
6
3
1 2 3 1 2 3
Output
Exception in thread "main" java.lang.StackOverflowError
at deven.pivot(deven.java:99)
at deven.select(deven.java:34)
at deven.pivot(deven.java:102)
at deven.select(deven.java:34)
at deven.select(deven.java:59)
at deven.select(deven.java:59)
at deven.select(deven.java:59)
If you maintained an equalsCount in addition to your smallerCount, you should be able to detect whether your candidate value is the median when it is also a duplicate.
(Explanation)
You appear to be deliberately returning -1 as an invalid value when your median method fails unexpectedly. It would be more proper to throw an exception of some sort, but what you really want is for it to never reach that point.
Your algorithm fails when the median is a duplicate. In the set { 1, 2, 2, 2, 3 }, for example, 2 is the obvious median, but there's never a point where there are exactly 2 values "smaller than" any of the values being verified.
If you count both smaller and equal values, then you can know your candidate to be a median if either your current test passes, or if the smaller count is less than the midpoint AND the smaller + equal count is greater than the midpoint.
The problem is your median method. It should not return -1. In the last line of the median method, instead of
return -1;
change it to
return array[rand.nextInt(array.length)];
Please note that this fix is just an attempt to fix the error you have. It's not a good fix in the sense that median method does not return the median. I think the application should be refactored. The idea of the fix is actually in the pivot method. A good pivot is the median. But if you cannot find the median efficiently, then a pivot can be a random choice among the array.
Update:
Let's fix the median method:
static int median(int[] array) {
if (array.length == 0) {
throw new IllegalArgumentException("array cannot be empty.");
}
int mid = array.length / 2;
for (int candidate : array) {
int lower = 0;
int higher = 0;
for (int value : array) {
if (value < candidate) {
lower++;
}
else if (value > candidate) {
higher++;
}
}
if (lower <= mid && higher <= mid) {
return candidate;
}
}
throw new IllegalStateException();
}