Median Algorithm for 4 sorted arrays - java

I need to write an Algorithm for my course, to find the middle value of 4 sorted arrays different sizes in O(n), and i'm not allowed to create an array to store the data.
how should I approach the problem? I thought about running on a loop with 4 indexes as if i'm sorting the arrays into a big array but instead just run without storing the data. the loop will stop at n/2 and it should provide me the middle value.
writing it seems complex and very messy (i need to check for 4 of the arrays if i'm out of bound), is there a better way to approach this?

I think you're on to the key idea: the median value of all the values in four arrays is just the median of all the values, so if we get half way through all the values then whatever is next is the median. I would suggest structuring as follows:
int firstIndex = 0;
int secondIndex = 0;
int thirdIndex = 0;
int fourthIndex = 0;
double current;
for (int i = 0; i < n/2; i++) {
// 1.) Find the value out of the four at firstIndex, secondIndex, ...
// which is smallest, and assign it to current
// 2.) Increment whichever of the four indices belongs to that element
}
// whatever is in current at the end of the loop is the middle element
You probably want a function findMin(int index1, int index2, int index3, int index4). This method could also be responsible for the out-of-bounds checks, so the main loop could just rely on it to be pointed in the right direction, and not care if it's run out of elements in any given array.
Does this make sense? I've tried to leave enough ambiguity to let you handle most of the real implementation work :)

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().
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;
}
}

Related

Given an array return true if you can split it to two equal groups recursively

Method name:
public static boolean equalSplit (int[] a)
if you can split an array to two and the total of the values are equal return true,example:
{-3,5,12,14,-9,13} // returns true -3+5+14 = 12+(-9)+13
{-3,5,-12,14,-9,13}; //return false,you can split it to two groups but the groups won`t be equal 3+5+14+(-12)=-9+13
{-3,5,12,14,-9}; // false because can`t split the array to two
Changing the array order is not allowed, recursion only no loops allowed, private methods are fine as long as
recursive as well.
What i wrote(code not complete):
public class Rec
{
// private method to find total sum of an array.
static int findSum(int A[], int N)
{
if (N <= 0)
return 0;
return (findSum(A, N - 1) + A[N - 1]);
}
//
public static boolean equalSplit (int[] a)
{
return(equalSplit(a,0,0));
}
// override
private static boolean equalSplit (int[] a,int sum,int i)
{
int totalSum = findSum(a,a.length); // total sum of the given array.
if(i > a.length) // run until reach the end of the array.
return false;
if(totalSum - sum == sum) // if subtracting the recursive sum from total sum gives equal number return true
return true;
int take = equalSplit(a,sum + a[i] , i+1); // boolean cannot be convereted to int
}
}
What I'm trying to do:
I used a private method to find the sum of the whole array, and subtract from the total sum. The sum in the main method that suppose to sum the array step by step. My problem is that the method is boolean and i have no idea how to use boolean method recursively
to complete it.
My questions:
Can you tell me if the structure is good? and how should I approach it?
Here's a solution without using loops and not changing the orders,
static int[] arrA, arrB;
public static boolean equalSplit(int[] arr) {
//Step 1
if (arr.length % 2 == 0) {
int sumA = 0, sumB = 0; // Two int variables to store the value of sum.
// Initializing the two new arrays with equal length.
arrA = new int[arr.length / 2];
arrB = new int[arr.length / 2];
// Copying the elements from the given array to the new arrays.
arrA = createArray(arrA, 0, arr, 0);
arrB = createArray(arrB, 0, arr, arr.length / 2);
//Calculating and storing the sum in the variables.
sumA = arraySum(arrA, arrA.length);
sumB = arraySum(arrB, arrB.length);
return sumA == sumB; // Checking the codition
} else {
return false;
}
}
private static int[] createArray(int[] arr, int index, int[] copyFrom, int copyFromIndex) {
if(index == arr.length) return arr;
arr[index] = copyFrom[copyFromIndex];
index++;
copyFromIndex++;
return createArray(arr, index, copyFrom, copyFromIndex);
}
private static int arraySum(int[] arr, int N) {
if (N <= 0) return 0;
return (arraySum(arr, N - 1) + arr[N - 1]);
}
My approach towards this question is,
Step 1 -> Checking whether can you split the given array into two equal arrays. If yes next comes the Step 2 or return false without any futher steps.
Step 2 -> Copying the given array elements into two different but equal arrays using recursion.
Step 3 -> Sum the newly populated two arrays and store it in two different variable.
Step 4 -> If the Sum of both the newly populated arrays is equal then the function return true else false.
Explanation :
Create two new integer arrays which are going to get populated only
if the given array can be divided into two equal parts. Here it is
arrA and arrB.
Check whether if the length of given array can be divided by two and have 0 remainders because this can give the answer to the question "Can this array be divided into two equal parts ?". The piece of code in this answer is arr.length % 2 == 0. If the given array satisfies this condition only then the steps given below will be carried out else it will return false.
Initialize two integer variable to store the value of Sum of both the equally divided arrays.
Initialize the two newly created arrays with the array length of half the given array which is arr.length / 2.
Then copy first half of given array elements to the first newly initialized array then the second half to the second array. To achieve this createArray(int[] arr, int index, int[] copyFrom, int copyFromIndex) method is used. arr is the argument to pass the array which should be copied to, index should be 0 because it is used as the index of newly created arrays, copyFrom is a parameter for the given array which has all the elements, copyFromIndex is used to start copying the elements from the given index.
Then calculate the sum using recursive function and store it in separate variable which was created earlier. The function used here was arraySum(int[] arr, int N).
Return whether both the sum variables are equal.

How to make Quicksort code stable without libraries? (Java)

I am currently trying to make a Quicksort in java. The only problem is that I just can't make it stable (so that the order of reccurring elements is still the same). My code so far:
Update: Thank you for all your answers but sadly I 'm not allowed to use any libraries like java.util for LinkedLists etc.
public void quickSortStable(Integer[] data) {
int IndexZero = 0;
int IndexLength = data.length-1;
sortQuicksortArray(data, IndexZero, IndexLength);
}
public int createQuicksortPartition(Integer[] data, int IndexZero, int IndexLength){
int pivot = data[IndexLength];
int i = (IndexZero-1);
for (int j=IndexZero; j<IndexLength; j++)
{
if (data[j] < pivot)
{
i++;
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
int temp = data[i+1];
data[i+1] = data[IndexLength];
data[IndexLength] = temp;
return i+1;
}
public void sortQuicksortArray(Integer[] data, int IndexZero, int IndexLength){
if (IndexZero < IndexLength)
{
int partition = createQuicksortPartition(data, IndexZero, IndexLength);
sortQuicksortArray(data, IndexZero, partition-1);
sortQuicksortArray(data, partition+1, IndexLength);
}
}
The quicksort algorithm is not stable by nature.
There are already some good answers on quora.
In short, each partition is not stable, because quick sort may swap the outer elements before the middle elements.
for example,
// original
4(a) 4(b) 3 2(a) 2(b)
^ ^
// after first partition
2(b) 4(b) 3 2(a) 4(a)
^ ^
// after second partition
2(b) 2(a) 3 4(b) 4(a)
Since the partition is not stable, the overall algorithm cannot be stable.
You can make the quicksort sorting stable when you save the elements which are smaller or bigger than the pivot in two temporary lists (or one array) and add them back to the original input array when you have separated the values. The pseudo algorithm looks like this:
public int createQuicksortPartition(Integer[] data, int startIndex, int endIndex){
List<Integer> lower = new ArrayList<Integer>();
List<Integer> higher = new ArrayList<Integer>();
Integer pivot = data[endIndex];
for (int i=startIndex; i<endIndex; i++) {
if (data[i] < pivot) {
lower.add(data[i]);
} else {
higher.add(data[i]);
}
// readd them to the input array
for (int i=0; i<lower.size(); i++) {
data[startIndex+i] = lower.get(i);
}
data[startIndex+lower.size()] = pivot;
for (int i=0; i<higher.size(); i++) {
data[startIndex+lower.size()+i] = higher.get(i);
}
return startIndex+lower.size();
}
(untested pseudo code)
This obviously need O(n) additional space to have a copy of the data to sort. You also have to take extra care for the pivot element and the "higher" elements, which are equal to that pivot. These have to added before the pivot element to ensure that the sorting is stable, because the pivot element was the last element from the input array. In this case the ordering should be:
Elements smaller than the pivot
Elements equal the pivot
The pivot itself
Elements greater than the pivot
You can solve this by using three lists for smaller, equal and greater values and add them back to the input array accordingly.

How to return all array permutations iteratively into a two-dimensional array?

I am trying to write a program that will iterate through all possible permutations of a String array, and return a two dimensional array with all the permutations. Specifically, I am trying to use a String array of length 4 to return a 2D array with 24 rows and 4 columns.
I have only found ways to print the Strings iteratively but not use them in an array. I have also found recursive ways of doing it, but they do not work, as I am using this code with others, and the recursive function is much more difficult.
For what I want the code to do, I know the header should be:
public class Permutation
{
public String[][] arrayPermutation(String[] str)
{
//code to return 2D array
}
}
//I tried using a recursive method with heap's algorithm, but it is very //complex with its parameters.
I am very new to programming and any help would be greatly appreciated.
Your permutation-problem is basically just an index-permutation problem.
If you can order the numbers from 0 to n - 1 in all possible variations, you can use them as indexes of your input array, and simply copy the Strings. The following algorithm is not optimal, but it is graphic enough to explain and implement iteratively.
public static String[][] getAllPermutations(String[] str) {
LinkedList<Integer> current = new LinkedList<>();
LinkedList<Integer[]> permutations = new LinkedList<>();
int length = str.length;
current.add(-1);
while (!current.isEmpty()) {
// increment from the last position.
int position = Integer.MAX_VALUE;
position = getNextUnused(current, current.pop() + 1);
while (position >= length && !current.isEmpty()) {
position = getNextUnused(current, current.pop() + 1);
}
if (position < length) {
current.push(position);
} else {
break;
}
// fill with all available indexes.
while (current.size() < length) {
// find first unused index.
int unused = getNextUnused(current, 0);
current.push(unused);
}
// record result row.
permutations.add(current.toArray(new Integer[0]));
}
// select the right String, based on the index-permutation done before.
int numPermutations = permutations.size();
String[][] result = new String[numPermutations][length];
for (int i = 0; i < numPermutations; ++i) {
Integer[] indexes = permutations.get(i);
String[] row = new String[length];
for (int d = 0; d < length; ++d) {
row[d] = str[indexes[d]];
}
result[i] = row;
}
return result;
}
public static int getNextUnused(LinkedList<Integer> used, Integer current) {
int unused = current != null ? current : 0;
while (used.contains(unused)) {
++unused;
}
return unused;
}
The getAllPermutations-method is organized in an initialization part, a loop collecting all permutations (numeric), and finally a convertion of the found index-permutation into the String-permutations.
As the convertion from int to String is trivial, I'll just explain the collection part. The loop iterates as long, as the representation is not completely depleted, or terminated from within.
First, we increment the representation (current). For that, we take the last 'digit' and increment it to the next free value. Then we pop, if we are above length, and look at the next digit (and increment it). We continue this, until we hit a legal value (one below length).
After that, we fill the remainder of the digits with all still remaining digits. That done, we store the current representation to the list of arrays.
This algorithm is not optimal in terms of runtime! Heap is faster. But implementing Heap's iteratively requires a non-trivial stack which is tiresome to implement/explain.

Two sum - Doesn't work

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Consider input [3,2,4] and target is 6. I added (3,0) and (2,1) to the map and when I come to 4 and calculate value as 6 - 4 as 2 and when I check if 2 is a key present in map or not, it does not go in if loop.
I should get output as [1,2] which are the indices for 2 and 4 respectively
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] arr = new int[2];
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i = 0;i < len; i++)
{
int value = nums[i] - target;
if(map.containsKey(value))
{
System.out.println("Hello");
arr[0] = value;
arr[1] = map.get(value);
return arr;
}
else
{
map.put(nums[i],i);
}
}
return null;
}
I don't get where the problem is, please help me out
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice. Consider input [3,2,4] and target is 6. I added (3,0) and (2,1) to the map and when I come to 4 and calculate value as 6 - 4 as 2 and when I check if 2 is a key present in map or not, it does not go in if loop.
Okay, let's take a step back for a second.
You have a list of values, [3,2,4]. You need to know which two will add up 6, well, by looking at it we know that the answer should be [1,2] (values 2 and 4)
The question now is, how do you do that programmatically
The solution is (to be honest), very simple, you need two loops, this allows you to compare each element in the list with every other element in the list
for (int outter = 0; outter < values.length; outter++) {
int outterValue = values[outter];
for (int inner = 0; inner < values.length; inner++) {
if (inner != outter) { // Don't want to compare the same index
int innerValue = values[inner];
if (innerValue + outterValue == targetValue) {
// The outter and inner indices now form the answer
}
}
}
}
While not highly efficient (yes, it would be easy to optimise the inner loop, but given the OP's current attempt, I forewent it), this is VERY simple example of how you might achieve what is actually a very common problem
int value = nums[i] - target;
Your subtraction is backwards, as nums[i] is probably smaller than target. So value is getting set to a negative number. The following would be better:
int value = target - nums[i];
(Fixing this won't fix your whole program, but it explains why you're getting the behavior that you are.)
This code for twoSum might help you. For the inputs of integer array, it will return the indices of the array if the sum of the values = target.
public static int[] twoSum(int[] nums, int target) {
int[] indices = new int[2];
outerloop:
for(int i = 0; i < nums.length; i++){
for(int j = 0; j < nums.length; j++){
if((nums[i]+nums[j]) == target){
indices[0] = i;
indices[1] = j;
break outerloop;
}
}
}
return indices;
}
You can call the function using
int[] num = {1,2,3};
int[] out = twoSum(num,4);
System.out.println(out[0]);
System.out.println(out[1]);
Output:
0
2
You should update the way you compute for the value as follows:
int value = target - nums[i];
You can also check this video if you want to better visualize it. It includes Brute force and Linear approach:

Merge two unsorted integer arrays without using Set in Java

Given two integer arrays, create a third array containing non-duplicate values from both arrays. Can't use Set implementations in Java, here is how I solved it and I was hoping to find a solution with better runtime complexity.
My implementation:
public static void removeDuplicates(int[] arr1, int[] arr2){
int[] arr = new int[arr1.length + arr2.length];
int index=0,i,j;
for (i=0;i<arr1.length;i++){
if(!contains(arr, arr1[i])){
arr[index++]=arr1[i];
}
}
for (j = 0; j < arr2.length; j++) {
if (!contains(arr, arr2[j])) {
arr[index++] = arr2[j];
}
}
for (int a: arr)
System.out.println(a);
}
private static boolean contains(int[] arr, int i) {
for (int a: arr){
if(a==i) return true;
}
return false;
}
This is indeed of quadratic complexity due to the contains calls. You could improve your algorithm by first sorting both arrays, and then procede to a merging akin to what you would do in the merge step of a mergesort, but adding the entries only if the previous entry is not the same.
You'd have to keep a reference to the last index with data after the merge, so you can at the end resize your array to a smaller one and avoid empty cells.
update
Some precisions for the merge part: you would start at the beginning of both sorted arrays, and take the smaller of both items at this index, then increment the index for the array you took one. Considering your arrays a and b, target being your target array, i the index cursor for a, j for b and k for target:
you start with i = j = k = 0
you take v = min(a[i], b[j]) and increment the relevant index (i if you took from a, j if you took from b)
if target[k-1] == v (when k > 0 of course), you just increment k (i.e. ignore the value as it's already in the array)
else you do target[k++] = v (i.e. put v at index k in target and then increment k)
at the end you will have k equals to the real size of your target array so you can trim down the array to an array of size k <= a.length + b.length
Of course during the process, once you have exhausted one of the two arrays, you just take from the other and compare with the last value in target.

Categories

Resources