Sorting binary array using comparisons in Java - java

I am trying to implement a solution to sort a binary array containing 0 and 1 but it is comparison based. I am going with the approach take 1 index i (1st element of array) and 2nd index j last element of array. if i>j swap that element. else increment i and decrement j.
I am pretty new in java and programming.
Here is what I have tried until now:
My sort method:
public static void sort(int[] arr)
{
int i = arr[0];
int j = arr[arr.length-1];
for(int x=0;x<arr.length-1;x++)
{
int temp = 0;
if(i>j)
{
temp = i;
i=j;
j=temp;
i++;
j--;
}
else{
i++;
j--;
}
}
}
My main method
public static void main(String[] args) {
int[] binary = {0,0,1,1,0,1,1,1,1,0,1,0,0,0,1,1,0};
sort(binary);
}
Any help will be appreciated.
Thanks

Beyond the problems explained in the comments, I mocked up a solution to show how you might go about doing this correctly. I've also added some comments to explain the logic:
public class Main {
public static void main(String[] args)
{
int[] binary = {0,0,1,1,0,1,1,1,1,0,1,0,0,0,1,1,0};
sort(binary);
System.out.println(Arrays.toString(binary));
}
public static void sort(int[] arr)
{
int i = 0;
int j = arr.length - 1;
while(i < j)
{
//we only want to swap 1s to the right
if(arr[i] == 0)
//skip 0s
i++;
//we only want to swap 1s into places where 0s are
else if(arr[j] == 1)
//skip 1s
j--;
//if arr[i] is 1 and arr[j] is 0
else //we now know that arr[i] is 1 and arr[j] is 0
{
//move the 1 to the right
swap(arr, i, j);
//we just processed arr[i]
i++;
//we just processed arr[j]
j--;
}
}
}
private static void swap(int[] arr, int idx1, int idx2)
{
int temp = arr[idx1];
arr[idx1] = arr[idx2];
arr[idx2] = temp;
}
}
This can also be expressed in terms of a for loop, like so (though it's not recommended to make your code this hard to read):
public static void sort(int[] arr)
{
for(int i = 0, j = arr.length - 1; i < j; i += arr[i]^1, j -= arr[j])
if(arr[i] == 1 && arr[j] == 0)
swap(arr, i, j);
}
When I say "not recommended", recall the saying: "Just because you can, doesn't mean you should."
As per #Andreas' comment, you can just do:
arr[i] = 0;
arr[j] = 1;
instead of calls to swap. Alternatively for the dirty "not recommended" version, you can do:
arr[i] ^= arr[j] = 1;

Here is one approach. I simply start at the top and bottom and separately increment the indices until the conditions are met. Then replace the values.
int[] b = { 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
};
int a = 0;
int c = b.length - 1;
while (a < c) {
boolean flag1 = true;
boolean flag2 = true;
if (b[a] == 0) {
a++; // leave it there
flag1 = false;
}
//
if (b[c] == 1) {
c--; // leave it there
flag2 = false;
}
if (flag1 && flag2) {
b[c] = 1;
b[a] = 0;
}
}

Related

Recursive in Merge Sort

public static void main(String[] args) {
int[] numbers = {20,4,7,6,1,3,9,5};
mergeSort(numbers);
}
private static void mergeSort(int[] inputArray) {
int inputLength = inputArray.length;
System.out.println(inputLength);
if (inputLength < 2)
return;
int midIndex = inputLength / 2;
int[] leftHalf = new int[midIndex];
int[] rightHalf = new int[inputLength - midIndex];
for (int i = 0; i < midIndex; i++) {
leftHalf[i] = inputArray[i];
}
for (int i = midIndex; i < inputLength; i++) {
rightHalf[i - midIndex] = inputArray[i];
}
mergeSort(leftHalf);
mergeSort(rightHalf);
merge(inputArray, leftHalf, rightHalf);
}
private static void merge(int[] inputArray, int[] leftHalf, int[] rightHalf) {
int leftSize = leftHalf.length;
int rightSize = rightHalf.length;
int i = 0, j = 0, k = 0;
while (i < leftSize && j < rightSize) {
if (leftHalf[i] <= rightHalf[i]) {
inputArray[k] = leftHalf[i];
i++;
} else {
inputArray[k] = rightHalf[j];
j++;
}
k++;
}
while (i < leftSize) { //eğer karşılaştırılmayan bir tane kalırsa diye yapılıyor yani
inputArray[k] = leftHalf[i];
i++;
k++;
}
while (j < rightSize) {
inputArray[k] = rightHalf[j];
j++;
k++;
}
}
In the mergeSort part if inputLength < 2 part of the code, we return when the length is less than 2. And last time the inputLength was 1, it becomes 2 and returns to the array [20,4].
This did not make sense to me logically. How does it get back to [20,4] when last we had [20] left?
first of all the code you have shared is flawed in the merge function part, you can find the proper code for Merge sort online, you can refer to
https://www.geeksforgeeks.org/java-program-for-merge-sort/
Now for understanding merge sort you have to understand the concept of stack (Last in First out) & recursion. In recursion the lines after the recursive call wait till the recursive call to the function has not executed completely. So in case of the
1st call Merge sort the length of the array is n and waiting for the complete execution of mergeSort(leftHalf) and mergeSort(rightHalf) both of size (n/2).
now for both the mergeSort(leftHalf) and mergeSort(rightHalf)
there will be sub left part and sub right part and this will continue till the size of the array becomes <2 and the remaining part will wait.
and after the successful execution of the smallest part it will return to the previous part from where this part was called. By this eventually this will return to the place where the function was called first.
And in case of your code both the smaller arrays are merged into the larger array so the data of the left and right sub array aren't lost.

26. Remove Duplicates from Sorted Array - Java

Question : Given a sorted array nums, remove the duplicates in-place such that each element appears only once and returns the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
public int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
if (nums[j] != nums[i]) {
i++;
nums[i] = nums[j];
}
}
return i + 1;
}
What exactly does the return statement do here. What does return i + 1 mean here ?
The return i + 1 is returning how many unique integers are there. I believe this is a Leetcode problem, and since its in place, the int[] is passed in by reference, Leetcode wants to know how many numbers to check (you're supposed to put the unique numbers in the first i + 1 spots).
If you look at the question, it says:
Which means that you return the length of the array.
So, if you have the array [1,1,2,3,4,4], you would turn that into [1,2,3,4,...], where the ... is the rest of the array. However, you return 4 because the length of the new array should be 4.
Hope this clears things up for you!
Your question has been already answered here; in addition to that, we can also start from zero and remove the first if statement:
Test with a b.java file:
import java.util.*;
class Solution {
public static final int removeDuplicates(
final int[] nums
) {
int i = 0;
for (int num : nums)
if (i == 0 || num > nums[i - 1]) {
nums[i++] = num;
}
return i;
}
}
class b {
public static void main(String[] args) {
System.out.println(new Solution().removeDuplicates(new int[] { 1, 1, 2}));
System.out.println(new Solution().removeDuplicates(new int[] { 0, 0, 1, 1, 1, 2, 2, 3, 3, 4}));
}
}
prints
2
5
I tried in this easy way. Here Time complexity is O(n) and space
complexity: O(1).
static int removeDuplicates(int[] nums){
if(nums.length == 0) {
return 0;
}
int value = nums[0];
int lastIndex = 0;
int count = 1;
for (int i = 1; i < nums.length; i++) {
if(nums[i] > value) {
value = nums[i];
lastIndex = lastIndex+1;
nums[lastIndex] = value;
count++;
}
}
return count;
}
class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n == 0 || n == 1)
return n;
int j = 0;
for (int i=0; i<n-1; i++)
if (nums[i]!= nums[i+1])
nums[j++] = nums[i];
nums[j++]=nums[n-1];
return j;
}
}
public class RemoveDuplicateSortedArray {
//Remove Duplicates from Sorted Array
public static void main(String[] args) {
int[] intArray = new int[]{0, 0, 1, 1, 1, 2, 2, 3, 3, 4};
int count = extracted(intArray);
for (int i = 0; i < count; i++) {
System.out.println(intArray[i]);
}
}
private static int extracted(int[] intArray) {
int size = intArray.length;
int count = 1;
if (size == 1) {
return 1;
} else if (size == 2) {
if (intArray[0] == intArray[1]) {
return 1;
} else {
return 2;
}
} else {
for (int i = 0, j = i + 1; j < size; j++) {
if (intArray[i] < intArray[j]) {
i++;
intArray[i] = intArray[j];
count++;
}
}
return count;
}
}
}

issues with codingbat maxMirror exercise

So basically, I've been going through these codingBat problems, and when I get really stuck, I usually check out the solution and trace the logic and that has helped me not get stuck on later problems which used similar ideas.
This max mirror problem is not like the others for me personally; I have no idea how to actually write the code to solve it, even forming the algorithm is kind of tricky for me
We'll say that a "mirror" section in an array is a group of contiguous elements such that somewhere in the array, the same group appears in reverse order. For example, the largest mirror section in {1, 2, 3, 8, 9, 3, 2, 1} is length 3 (the {1, 2, 3} part). Return the size of the largest mirror section found in the given array.
maxMirror({1, 2, 3, 8, 9, 3, 2, 1}) → 3
maxMirror({1, 2, 1, 4}) → 3
maxMirror({7, 1, 2, 9, 7, 2, 1}) → 2
Now, in terms of the algorithm, I sort of want to say something like, if we start by checking if the whole array is a mirror and then decrease the checked area size by 1 if it's not. But in terms of the pseudocode and the real code I have no idea.
My go to solution in cases like this where what your code should be doing is always doing it manually, then figuring out the essence of how it is that I am tackling the solution.
For this problem I found myself looking at possible subsets of the original array, then looking backwards through the original array to see if I can find that same subset again.
Next, I translated that into pseudocode,
for each segment in nums
check if nums contains segment backwards
Repeated, but this time with more implementation details worked out.
for each segment in nums, starting with the largest
reverse the segment
check if nums contains reversed segment
if it does, return the size of that segment
Next, find some likely candidates for methods in the pseudocode and write them. I chose to do this for "reverse" and "contains":
private int[] reverse(int[] nums) {
int[] rtn = new int[nums.length];
for (int pos = 0; pos < nums.length; pos++) {
rtn[nums.length - pos - 1] = nums[pos];
}
return rtn;
}
private boolean contains(int[] nums, int[] segment) {
for (int i = 0; i <= nums.length - segment.length; i++) {
boolean matches = true;
for (int j = 0; j < segment.length; j++) {
if (nums[i + j] != segment[j]) {
matches = false;
break;
}
}
if (matches) return true;
}
return false;
}
Finally, implement the rest:
public int maxMirror(int[] nums) {
for (int window = nums.length; window > 0; window--) {
for (int pos = 0; pos <= nums.length - window; pos++) {
int[] segment = new int[window];
for (int innerpos = 0; innerpos < window; innerpos++) {
segment[innerpos] = nums[pos + innerpos];
}
segment = reverse(segment);
if (contains(nums, segment)) {
return window;
}
}
}
return 0;
}
My irrelevant two cents....
public int maxMirror(int[] nums) {
// maximum mirror length found so far
int maxlen= 0;
// iterate through all possible mirror start indexes
for (int front = 0; front < nums.length; front++) {
// iterate through all possible mirror end indexes
for (int back = nums.length - 1; back >= front; back--) {
// this inner for-loop determines the mirror length given a fixed
// start and end index
int matchlen = 0;
Boolean match = (nums[front] == nums[back]);
// while there is a match
// 1. increment matchlen
// 2. keep on checking the proceeding indexes
while (match) {
matchlen++;
int front_index = front + matchlen;
int back_index = back - matchlen;
// A match requires
// 1. Thee indexes are in bounds
// 2. The values in num at the specified indexes are equal
match =
(front_index < nums.length) &&
(back_index >= 0) &&
(nums[front_index] == nums[back_index]);
}
// Replace the max mirror length with the new max if needed
if (matchlen > maxlen) maxlen = matchlen;
}
}
return maxlen;
}
Alternative solution designed to confuse you
public int maxMirror(int[] nums) {
return maxlen_all_f(nums, 0);
}
int maxlen_all_f(int [] nums, int f) {
return (f >= nums.length)
? 0
: max(
maxlen_for_start_f(nums, f, nums.length - 1),
maxlen_all_f(nums, f + 1)
);
}
int max(int a, int b){
return (a > b)
? a
: b;
}
int maxlen_for_start_f(int [] nums, int f, int b) {
return (b < f)
? 0
: max(
matchlen_f(nums, f, b),
maxlen_for_start_f(nums, f, b - 1)
);
}
int matchlen_f(int[] nums, int f, int b) {
return match_f(nums, f, b)
? 1 + matchlen_f(nums, f + 1, b - 1)
: 0;
}
Boolean match_f(int [] nums, int a, int b) {
return (a < nums.length && b >= 0) && (nums[a] == nums[b]);
}
The solution is simple rather than making it complex:
public static int maxMirror(int[] nums) {
final int len=nums.length;
int max=0;
if(len==0)
return max;
for(int i=0;i<len;i++)
{
int counter=0;
for(int j=(len-1);j>i;j--)
{
if(nums[i+counter]!=nums[j])
{
break;
}
counter++;
}
max=Math.max(max, counter);
}
if(max==1)
max=0;
return max;
}
This is definitely not the best solution in terms of performance. Any further improvements are invited.
public int maxMirror(int[] nums) {
int maxMirror=0;
for(int i=0;i<nums.length;i++)
{
int mirror=0;
int index=lastIndexOf(nums,nums[i]);
if(index!=-1){
mirror++;
for(int j=i+1;j<nums.length;j++)
{
if(index>=0&&existsInReverse(nums,index,nums[j]))
{
mirror++;
index--;
continue;
}
else
break;
}
if(mirror>maxMirror)
maxMirror=mirror;
}
}
return maxMirror;
}
int lastIndexOf(int[] nums,int num){
for(int i=nums.length-1;i>=0;i--)
{
if(nums[i]==num)
return i;
}
return -1;
}
boolean existsInReverse(int nums[],int startIndex,int num){
if(startIndex!=0&&(nums[startIndex-1]==num))
return true;
return false;
}
Here is my answer , Hope the comments explain it well :)
public int maxMirror(int[] nums) {
int max = 0;
// our largest mirror section found stored in max
//iterating array
for(int i=0;i<nums.length;i++){
int iterator = i; // iterator pointing at one element of array
int counter = 0;//counter to count the mirror elements
//Looping through for the iterator element
for(int j=nums.length-1;j>=i;j--){
//found match i.e mirror element
if(nums[iterator] == nums[j]){
iterator++; // match them until the match ends
counter++; // counting the matched ones
}
else{
//matching ended
if(counter >= max){//checking if previous count was lower than we got now
max = counter; // store the count of matched elements
}
counter = 0; // reset the counter
iterator = i; // reset the iterator for matching again
}
}
if(counter >= max){//checking if previous count was lower than we got now
max = counter;// store the count of matched elements at end of iteration
}
}
return max;//return count
}

Solving codingBat 'evenOdd' with one loop in Java

The question is about Solving this problem from codingBat in Java.
Problem Statement:
Return an array that contains the exact same numbers as the given array, but rearranged so that all the even numbers come before all the odd numbers. Other than that, the numbers can be in any order. You may modify and return the given array, or make a new array.
evenOdd({1, 0, 1, 0, 0, 1, 1}) → {0, 0, 0, 1, 1, 1, 1}
evenOdd({3, 3, 2}) → {2, 3, 3}
evenOdd({2, 2, 2}) → {2, 2, 2}
The Problem is simple with 2 loops I attempted at solving it with 1 it got too lengthy I believe, is there any other efficient way to solve the above problem using 1 loop?
do not use collections!
My solution:
public int[] evenOdd(int[] nums) {
boolean oddFound=false;
int count=-1;
int oddGap=0;
for(int i=0;i<nums.length;i++)
{
if(!(oddFound)&(nums[i]%2==0))
continue;
if((!oddFound)&(nums[i]%2==1))
{
oddFound=true;
count=i;
continue;
}
if((oddFound)&(nums[i]%2==1))
{
oddGap++;
continue;
}
if((oddFound)&(nums[i]%2==0))
{
int temp=nums[count];
nums[count]=nums[i];
nums[i]=temp;
if(i>0)
i--;
if(oddGap>0)
{
oddGap--;
count+=1;
oddFound=true;
continue;
}
oddFound=false;
}
}
return nums;
}
Since creating a new array is allowed, and the order of the numbers is irrelevant, I would use the following approach:
public int[] evenOdd(int[] nums) {
int[] output = new int[nums.length];
int evenPos = 0;
int oddPos = nums.length-1;
for (int i : nums) {
if (i%2==0) {
output[evenPos++]=i;
} else {
output[oddPos--]=i;
}
}
return output;
}
Update: A somewhat less readable version that doesn't require an extra array (along the lines of what #Seelenvirtuose suggests, just without the extra loops)
public int[] evenOdd(int[] nums) {
int evenPos = 0;
int oddPos = nums.length-1;
while (true) {
if (evenPos>=oddPos || evenPos>=nums.length || oddPos<0) {
break;
}
if (nums[evenPos]%2==0) {
evenPos++;
}
if (nums[oddPos]%2!=0) {
oddPos--;
}
if (evenPos<oddPos && nums[evenPos]%2 != 0 && nums[oddPos]%2 == 0) {
int tmp = nums[evenPos];
nums[evenPos] = nums[oddPos];
nums[oddPos] = tmp;
oddPos--;
evenPos++;
}
}
return nums;
}
You do not need any temporary lists or array because you can reorder the elements in-situ.
This is a simple algorithm:
Define two pointers, left and right (initially set to the bounds of the array).
As long as left does not exceed right and nums[left] is even, increment left.
As long as right does not exceed left and nums[right] is odd, decrement right.
If left is still less than right, swap the elements at positions left and right.
Repeat 2,3,4 as long as left is still less than right.
Got it? Here some code:
public int[] evenOdd(int[] nums) {
// (1)
int left = 0;
int right = nums.length -1;
do {
// (2)
while (left < right && nums[left] % 2 == 0)
left += 1;
// (3)
while (right > left && nums[right] % 2 != 0)
right -= 1;
// (4)
if (left < right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
} while (left < right); // (5)
return nums;
}
Okay! I finally jumped across this question which is actually closed but the solution by asker was almost there apart from failing in 2 cases which I fixed:
I commented out he code by asker which was making it fail in a couple of cases as seen in the question.
I think below is the simplest and most optimized solution:
public int[] evenOdd(int[] nums) {
int y=nums.length,x,a=0;
int temp=0;
for(x=0;x<y;x++)
{
if(nums[x]%2==0) {
if(a>(y-2))
return nums;
else{
//nums[a]=nums[a]+nums[x];
//nums[x]=nums[a]-nums[x];
//nums[a]=nums[a]-nums[x];
temp=nums[a];
nums[a]=nums[x];
nums[x]=temp;
a+=1;
}
}
return nums;
}
Traverse evenOdd from 0 to N.
for every even number encountered, copy it to the required position on the evenOdd array.
for every odd num encountered, store it in a separate array called oddnum.
After traversing the whole array, just copy the elements from oddnum to the Back of evenOdd.
Ex: evenOdd = {5,2,1,4}
Step 1. copy 5 to oddnum[0]
2. copy 2 to evenodd[0]
3. copy 1 to oddnum[1]
4. copy 1 to evenodd[1]
5. cpy oddnum[0] to evenOdd[2] and oddnum[1] to evenOdd[3]
Keeping to your restrictions, here's a one-loop answer:
public int[] evenOdd(int[] nums) {
int[] result = new int[nums.length];
int nextEven = 0;
int nextOdd = nums.length - 1;
for ( int num : nums )
{
if ( num % 2 == 0 )
result[ nextEven++ ] = num;
else
result[ nextOdd-- ] = num;
}
return result;
}
public int[] evenOdd(int[] nums) {
int count = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] % 2 == 0) {
int temp = nums[i];
nums[i] = nums[count];
nums[count] = temp;
count++;
}
}
return nums;
}
public int[] evenOdd(int[] nums) {
Stack stack = new Stack();
int[] nums2 = new int[nums.length];
for(int i = 0; i < nums.length; i++) {
if(nums[i] % 2 != 0) {
stack.push(nums[i]);
}
}
for(int i = 0; i < nums.length; i++) {
if(nums[i] % 2 == 0) {
stack.push(nums[i]);
}
}
for(int i = 0; i < nums.length; i++) {
nums2[i] = (Integer) stack.pop();
}
return nums2;
}
In-place version (stable):
We continually search for te first and last invalid values (first odd, before last even) and keep swapping them until they cross:
public int[] evenOdd(int[] nums) {
int first = 0, last = nums.length - 1;
while (first < last) {
while ((first < last) && isOdd(nums[last])) last--;
while ((first < last) && !isOdd(nums[first])) first++;
swap(nums, first, last);
}
return nums;
}
boolean isOdd(int num) { return (num & 1) == 1; }
void swap(int[] nums, int i, int j) {
int copy = nums[i];
nums[i] = nums[j];
nums[j] = copy;
}
With auxiliaries (stable):
We partition the even and odd values in separate lists and concatenate them back:
public int[] evenOdd(int[] nums) {
List<Integer> evens = new ArrayList<Integer>(nums.length);
List<Integer> odds = new ArrayList<Integer>(nums.length);
for (int num : nums)
if (isOdd(num)) odds.add(num);
else evens.add(num);
int[] results = new int[nums.length];
int i = 0;
for (int num : evens) results[i++] = num;
for (int num : odds) results[i++] = num;
return results;
}
boolean isOdd(int num) { return (num & 1) == 1; }
Simplified solution which uses Srteam API:
public int[] evenOdd(int[] nums) {
int[] evenOddArr = new int[nums.length];;
int[] evenArr = Arrays.stream(nums).filter(x -> x % 2 == 0).toArray();;
int[] oddArr = Arrays.stream(nums).filter(x -> x % 2 != 0).toArray();
evenOddArr = java.util.stream.IntStream.concat(Arrays.stream(evenArr), Arrays.stream(oddArr))
.toArray();
return evenOddArr;
}
It passes all the tests on CodingBat:

How to merge two sorted arrays into a sorted array? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
This was asked of me in an interview and this is the solution I provided:
public static int[] merge(int[] a, int[] b) {
int[] answer = new int[a.length + b.length];
int i = 0, j = 0, k = 0;
while (i < a.length && j < b.length)
{
if (a[i] < b[j])
{
answer[k] = a[i];
i++;
}
else
{
answer[k] = b[j];
j++;
}
k++;
}
while (i < a.length)
{
answer[k] = a[i];
i++;
k++;
}
while (j < b.length)
{
answer[k] = b[j];
j++;
k++;
}
return answer;
}
Is there a more efficient way to do this?
Edit: Corrected length methods.
public static int[] merge(int[] a, int[] b) {
int[] answer = new int[a.length + b.length];
int i = 0, j = 0, k = 0;
while (i < a.length && j < b.length)
answer[k++] = a[i] < b[j] ? a[i++] : b[j++];
while (i < a.length)
answer[k++] = a[i++];
while (j < b.length)
answer[k++] = b[j++];
return answer;
}
Is a little bit more compact but exactly the same!
I'm surprised no one has mentioned this much more cool, efficient and compact implementation:
public static int[] merge(int[] a, int[] b) {
int[] answer = new int[a.length + b.length];
int i = a.length - 1, j = b.length - 1, k = answer.length;
while (k > 0)
answer[--k] =
(j < 0 || (i >= 0 && a[i] >= b[j])) ? a[i--] : b[j--];
return answer;
}
Points of Interests
Notice that it does same or less number of operations as any other O(n) algorithm but in literally single statement in a single while loop!
If two arrays are of approximately same size then constant for O(n) is same. However if arrays are really imbalanced then versions with System.arraycopy would win because internally it can do this with single x86 assembly instruction.
Notice a[i] >= b[j] instead of a[i] > b[j]. This guarantees "stability" that is defined as when elements of a and b are equal, we want elements from a before b.
A minor improvement, but after the main loop, you could use System.arraycopy to copy the tail of either input array when you get to the end of the other. That won't change the O(n) performance characteristics of your solution, though.
Any improvements that could be made would be micro-optimizations, the overall algorithm is correct.
This solution also very similar to other posts except that it uses System.arrayCopy to copy the remaining array elements.
private static int[] sortedArrayMerge(int a[], int b[]) {
int result[] = new int[a.length +b.length];
int i =0; int j = 0;int k = 0;
while(i<a.length && j <b.length) {
if(a[i]<b[j]) {
result[k++] = a[i];
i++;
} else {
result[k++] = b[j];
j++;
}
}
System.arraycopy(a, i, result, k, (a.length -i));
System.arraycopy(b, j, result, k, (b.length -j));
return result;
}
Here is updated function. It removes duplicates, hopefully someone will find this usable:
public static long[] merge2SortedAndRemoveDublicates(long[] a, long[] b) {
long[] answer = new long[a.length + b.length];
int i = 0, j = 0, k = 0;
long tmp;
while (i < a.length && j < b.length) {
tmp = a[i] < b[j] ? a[i++] : b[j++];
for ( ; i < a.length && a[i] == tmp; i++);
for ( ; j < b.length && b[j] == tmp; j++);
answer[k++] = tmp;
}
while (i < a.length) {
tmp = a[i++];
for ( ; i < a.length && a[i] == tmp; i++);
answer[k++] = tmp;
}
while (j < b.length) {
tmp = b[j++];
for ( ; j < b.length && b[j] == tmp; j++);
answer[k++] = tmp;
}
return Arrays.copyOf(answer, k);
}
It can be done in 4 statements as below
int a[] = {10, 20, 30};
int b[]= {9, 14, 11};
int res[]=new int[a.legth+b.length];
System.arraycopy(a,0, res, 0, a.length);
System.arraycopy(b,0,res,a.length, b.length);
Array.sort(res)
GallopSearch Merge: O(log(n)*log(i)) rather than O(n)
I went ahead and implemented greybeard suggestion in the comments. Mostly because I needed a highly efficient mission critical version of this code.
The code uses a gallopSearch which is O(log(i)) where i is the
distance from the current index the relevant index exists.
The code uses a binarySearch for after the gallop search has
identified the proper,range. Since gallop limited this to a smaller
range the resulting binarySearch is also O(log(i))
The gallop and merge are performed backwards. This doesn't seem
mission critical but it allows in place merging of arrays. If one of
your arrays has enough room to store the results values, you can
simply use it as the merging array and the results array. You must specify the valid range within the array in such a case.
It does not require memory allocation in that case (big savings in critical operations). It simply makes sure it doesn't and cannot overwrite any unprocessed values (which can only be done backwards). In fact, you use the same array for both of the inputs and the results. It will suffer no ill effects.
I consistently used Integer.compare() so this could be switched out for other purposes.
There's some chance I might have goofed a little and not utilized information I have previously proven. Such as binary searching into a range of two values, for which one value was already checked. There might also be a better way to state the main loop, the flipping c value wouldn't be needed if they were combined into two operations in sequence. Since you know you will do one then the other everytime. There's room for for some polish.
This should be the most efficient way to do this, with time complexity of O(log(n)*log(i)) rather than O(n). And worst case time complexity of O(n). If your arrays are clumpy and have long strings of values together, this will dwarf any other way to do it, otherwise it'll just be better than them.
It has two read values at the ends of the merging array and the write value within the results array. After finding out which is end value is less, it does a gallop search into that array. 1, 2, 4, 8, 16, 32, etc. When it finds the range where the the other array's read value is bigger. It binary searches into that range (cuts the range in half, search the correct half, repeat until single value). Then it array copies those values into the write position. Keeping in mind that the copy is, by necessity, moved such that it cannot overwrite the same values from the either reading array (which means the write array and read array can be the same). It then performs the same operation for the other array which is now known to be less than the new read value of the other array.
static public int gallopSearch(int current, int[] array, int v) {
int d = 1;
int seek = current - d;
int prevIteration = seek;
while (seek > 0) {
if (Integer.compare(array[seek], v) <= 0) {
break;
}
prevIteration = seek;
d <<= 1;
seek = current - d;
if (seek < 0) {
seek = 0;
}
}
if (prevIteration != seek) {
seek = binarySearch(array, seek, prevIteration, v);
seek = seek >= 0 ? seek : ~seek;
}
return seek;
}
static public int binarySearch(int[] list, int fromIndex, int toIndex, int v) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = list[mid];
int cmp = Integer.compare(midVal, v);
if (cmp < 0) {
low = mid + 1;
} else if (cmp > 0) {
high = mid - 1;
} else {
return mid;// key found
}
}
return -(low + 1);// key not found.
}
static public int[] sortedArrayMerge(int[] a, int[] b) {
return sortedArrayMerge(null, a, a.length, b, b.length);
}
static public int[] sortedArrayMerge(int[] results, int[] a, int aRead, int b[], int bRead) {
int write = aRead + bRead, length, gallopPos;
if ((results == null) || (results.length < write)) {
results = new int[write];
}
if (aRead > 0 && bRead > 0) {
int c = Integer.compare(a[aRead - 1], b[bRead - 1]);
while (aRead > 0 && bRead > 0) {
switch (c) {
default:
gallopPos = gallopSearch(aRead, a, b[bRead-1]);
length = (aRead - gallopPos);
write -= length;
aRead = gallopPos;
System.arraycopy(a, gallopPos--, results, write, length);
c = -1;
break;
case -1:
gallopPos = gallopSearch(bRead, b, a[aRead-1]);
length = (bRead - gallopPos);
write -= length;
bRead = gallopPos;
System.arraycopy(b, gallopPos--, results, write, length);
c = 1;
break;
}
}
}
if (bRead > 0) {
if (b != results) {
System.arraycopy(b, 0, results, 0, bRead);
}
} else if (aRead > 0) {
if (a != results) {
System.arraycopy(a, 0, results, 0, aRead);
}
}
return results;
}
This should be the most efficient way to do it.
Some answers had a duplicate remove ability. That'll require an O(n) algorithm because you must actually compare each item. So here's a stand-alone for that, to be applied after the fact. You can't gallop through multiple entries all the way through if you need to look at all of them, though you could gallop through the duplicates, if you had a lot of them.
static public int removeDuplicates(int[] list, int size) {
int write = 1;
for (int read = 1; read < size; read++) {
if (list[read] == list[read - 1]) {
continue;
}
list[write++] = list[read];
}
return write;
}
Update: Previous answer, not horrible code but clearly inferior to the above.
Another needless hyper-optimization. It not only invokes arraycopy for the end bits, but also for the beginning. Processing any introductory non-overlap in O(log(n)) by a binarySearch into the data. O(log(n) + n) is O(n) and in some cases the effect will be pretty pronounced especially things like where there is no overlap between the merging arrays at all.
private static int binarySearch(int[] array, int low, int high, int v) {
high = high - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = array[mid];
if (midVal > v)
low = mid + 1;
else if (midVal < v)
high = mid - 1;
else
return mid; // key found
}
return low;//traditionally, -(low + 1); // key not found.
}
private static int[] sortedArrayMerge(int a[], int b[]) {
int result[] = new int[a.length + b.length];
int k, i = 0, j = 0;
if (a[0] > b[0]) {
k = i = binarySearch(b, 0, b.length, a[0]);
System.arraycopy(b, 0, result, 0, i);
} else {
k = j = binarySearch(a, 0, a.length, b[0]);
System.arraycopy(a, 0, result, 0, j);
}
while (i < a.length && j < b.length) {
result[k++] = (a[i] < b[j]) ? a[i++] : b[j++];
}
if (j < b.length) {
System.arraycopy(b, j, result, k, (b.length - j));
} else {
System.arraycopy(a, i, result, k, (a.length - i));
}
return result;
}
I had to write it in javascript, here it is:
function merge(a, b) {
var result = [];
var ai = 0;
var bi = 0;
while (true) {
if ( ai < a.length && bi < b.length) {
if (a[ai] < b[bi]) {
result.push(a[ai]);
ai++;
} else if (a[ai] > b[bi]) {
result.push(b[bi]);
bi++;
} else {
result.push(a[ai]);
result.push(b[bi]);
ai++;
bi++;
}
} else if (ai < a.length) {
result.push.apply(result, a.slice(ai, a.length));
break;
} else if (bi < b.length) {
result.push.apply(result, b.slice(bi, b.length));
break;
} else {
break;
}
}
return result;
}
Apache collections supports collate method since version 4; you can do this using the collate method in:
org.apache.commons.collections4.CollectionUtils
Here quote from javadoc:
collate(Iterable<? extends O> a, Iterable<? extends O> b, Comparator<? super O> c)
Merges two sorted Collections, a and b, into a single,
sorted List such that the ordering of the elements according to
Comparator c is retained.
Do not re-invent the wheel! Document reference:
http://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/CollectionUtils.html
Here's a shortened form written in javascript:
function sort( a1, a2 ) {
var i = 0
, j = 0
, l1 = a1.length
, l2 = a2.length
, a = [];
while( i < l1 && j < l2 ) {
a1[i] < a2[j] ? (a.push(a1[i]), i++) : (a.push( a2[j]), j++);
}
i < l1 && ( a = a.concat( a1.splice(i) ));
j < l2 && ( a = a.concat( a2.splice(j) ));
return a;
}
public class Merge {
// stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
public static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
// precondition: a[lo .. mid] and a[mid+1 .. hi] are sorted subarrays
assert isSorted(a, lo, mid);
assert isSorted(a, mid+1, hi);
// copy to aux[]
for (int k = lo; k <= hi; k++) {
aux[k] = a[k];
}
// merge back to a[]
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++) {
if (i > mid) a[k] = aux[j++];
else if (j > hi) a[k] = aux[i++];
else if (less(aux[j], aux[i])) a[k] = aux[j++];
else a[k] = aux[i++];
}
// postcondition: a[lo .. hi] is sorted
assert isSorted(a, lo, hi);
}
// mergesort a[lo..hi] using auxiliary array aux[lo..hi]
private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
merge(a, aux, lo, mid, hi);
}
public static void sort(Comparable[] a) {
Comparable[] aux = new Comparable[a.length];
sort(a, aux, 0, a.length-1);
assert isSorted(a);
}
/***********************************************************************
* Helper sorting functions
***********************************************************************/
// is v < w ?
private static boolean less(Comparable v, Comparable w) {
return (v.compareTo(w) < 0);
}
// exchange a[i] and a[j]
private static void exch(Object[] a, int i, int j) {
Object swap = a[i];
a[i] = a[j];
a[j] = swap;
}
/***********************************************************************
* Check if array is sorted - useful for debugging
***********************************************************************/
private static boolean isSorted(Comparable[] a) {
return isSorted(a, 0, a.length - 1);
}
private static boolean isSorted(Comparable[] a, int lo, int hi) {
for (int i = lo + 1; i <= hi; i++)
if (less(a[i], a[i-1])) return false;
return true;
}
/***********************************************************************
* Index mergesort
***********************************************************************/
// stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
private static void merge(Comparable[] a, int[] index, int[] aux, int lo, int mid, int hi) {
// copy to aux[]
for (int k = lo; k <= hi; k++) {
aux[k] = index[k];
}
// merge back to a[]
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++) {
if (i > mid) index[k] = aux[j++];
else if (j > hi) index[k] = aux[i++];
else if (less(a[aux[j]], a[aux[i]])) index[k] = aux[j++];
else index[k] = aux[i++];
}
}
// return a permutation that gives the elements in a[] in ascending order
// do not change the original array a[]
public static int[] indexSort(Comparable[] a) {
int N = a.length;
int[] index = new int[N];
for (int i = 0; i < N; i++)
index[i] = i;
int[] aux = new int[N];
sort(a, index, aux, 0, N-1);
return index;
}
// mergesort a[lo..hi] using auxiliary array aux[lo..hi]
private static void sort(Comparable[] a, int[] index, int[] aux, int lo, int hi) {
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, index, aux, lo, mid);
sort(a, index, aux, mid + 1, hi);
merge(a, index, aux, lo, mid, hi);
}
// print array to standard output
private static void show(Comparable[] a) {
for (int i = 0; i < a.length; i++) {
StdOut.println(a[i]);
}
}
// Read strings from standard input, sort them, and print.
public static void main(String[] args) {
String[] a = StdIn.readStrings();
Merge.sort(a);
show(a);
}
}
I think introducing the skip list for the larger sorted array can reduce the number of comparisons and can speed up the process of copying into the third array. This can be good if the array is too huge.
public int[] merge(int[] a, int[] b) {
int[] result = new int[a.length + b.length];
int aIndex, bIndex = 0;
for (int i = 0; i < result.length; i++) {
if (aIndex < a.length && bIndex < b.length) {
if (a[aIndex] < b[bIndex]) {
result[i] = a[aIndex];
aIndex++;
} else {
result[i] = b[bIndex];
bIndex++;
}
} else if (aIndex < a.length) {
result[i] = a[aIndex];
aIndex++;
} else {
result[i] = b[bIndex];
bIndex++;
}
}
return result;
}
public static int[] merge(int[] a, int[] b) {
int[] mergedArray = new int[(a.length + b.length)];
int i = 0, j = 0;
int mergedArrayIndex = 0;
for (; i < a.length || j < b.length;) {
if (i < a.length && j < b.length) {
if (a[i] < b[j]) {
mergedArray[mergedArrayIndex] = a[i];
i++;
} else {
mergedArray[mergedArrayIndex] = b[j];
j++;
}
} else if (i < a.length) {
mergedArray[mergedArrayIndex] = a[i];
i++;
} else if (j < b.length) {
mergedArray[mergedArrayIndex] = b[j];
j++;
}
mergedArrayIndex++;
}
return mergedArray;
}
Algorithm could be enhanced in many ways. For instance, it is reasonable to check, if a[m-1]<b[0] or b[n-1]<a[0].
In any of those cases, there is no need to do more comparisons.
Algorithm could just copy source arrays in the resulting one in the right order.
More complicated enhancements may include searching for interleaving parts and run merge algorithm for them only.
It could save up much time, when sizes of merged arrays differ in scores of times.
This problem is related to the mergesort algorithm, in which two sorted sub-arrays are combined into a single sorted sub-array. The CLRS book gives an example of the algorithm and cleans up the need for checking if the end has been reached by adding a sentinel value (something that compares and "greater than any other value") to the end of each array.
I wrote this in Python, but it should translate nicely to Java too:
def func(a, b):
class sentinel(object):
def __lt__(*_):
return False
ax, bx, c = a[:] + [sentinel()], b[:] + [sentinel()], []
i, j = 0, 0
for k in range(len(a) + len(b)):
if ax[i] < bx[j]:
c.append(ax[i])
i += 1
else:
c.append(bx[j])
j += 1
return c
You could use 2 threads to fill the resulting array, one from front, one from back.
This can work without any synchronization in the case of numbers, e.g. if each thread inserts half of the values.
//How to merge two sorted arrays into a sorted array without duplicates?
//simple C Coding
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
int InputArray1[] ={1,4,5,7,8,9,12,13,14,17,40};
int InputArray2[] ={4,5,11,14,15,17,18,19,112,122,122,122,122};
int n=10;
int OutputArray[30];
int i=0,j=0,k=0;
//k=OutputArray
while(i<11 && j<13)
{
if(InputArray1[i]<InputArray2[j])
{
if (k == 0 || InputArray1[i]!= OutputArray[k-1])
{
OutputArray[k++] = InputArray1[i];
}
i=i+1;
}
else if(InputArray1[i]>InputArray2[j])
{
if (k == 0 || InputArray2[j]!= OutputArray[k-1])
{
OutputArray[k++] = InputArray2[j];
}
j=j+1;
}
else
{
if (k == 0 || InputArray1[i]!= OutputArray[k-1])
{
OutputArray[k++] = InputArray1[i];
}
i=i+1;
j=j+1;
}
};
while(i<11)
{
if(InputArray1[i]!= OutputArray[k-1])
OutputArray[k++] = InputArray1[i++];
else
i++;
}
while(j<13)
{
if(InputArray2[j]!= OutputArray[k-1])
OutputArray[k++] = InputArray2[j++];
else
j++;
}
for(i=0; i<k; i++)
{
printf("sorted data:%d\n",OutputArray[i]);
};
}
var arrCombo = function(arr1, arr2){
return arr1.concat(arr2).sort(function(x, y) {
return x - y;
});
};
My favorite programming language is JavaScript
function mergeSortedArrays(a, b){
var result = [];
var sI = 0;
var lI = 0;
var smallArr;
var largeArr;
var temp;
if(typeof b[0] === 'undefined' || a[0]<b[0]){
smallArr = a;
largeArr = b;
} else{
smallArr = b;
largeArr = a;
}
while(typeof smallArr[sI] !== 'undefined'){
result.push(smallArr[sI]);
sI++;
if(smallArr[sI]>largeArr[lI] || typeof smallArr[sI] === 'undefined'){
temp = smallArr;
smallArr = largeArr;
largeArr = temp;
temp = sI;
sI = lI;
lI = temp;
}
}
return result;
}
Maybe use System.arraycopy
public static byte[] merge(byte[] first, byte[] second){
int len = first.length + second.length;
byte[] full = new byte[len];
System.arraycopy(first, 0, full, 0, first.length);
System.arraycopy(second, 0, full, first.length, second.length);
return full;
}
public static void main(String[] args) {
int[] arr1 = {2,4,6,8,10,999};
int[] arr2 = {1,3,5,9,100,1001};
int[] arr3 = new int[arr1.length + arr2.length];
int temp = 0;
for (int i = 0; i < (arr3.length); i++) {
if(temp == arr2.length){
arr3[i] = arr1[i-temp];
}
else if (((i-temp)<(arr1.length)) && (arr1[i-temp] < arr2[temp])){
arr3[i] = arr1[i-temp];
}
else{
arr3[i] = arr2[temp];
temp++;
}
}
for (int i : arr3) {
System.out.print(i + ", ");
}
}
Output is :
1, 2, 3, 4, 5, 6, 8, 9, 10, 100, 999, 1001,
You can use ternary operators for making the code a bit more compact
public static int[] mergeArrays(int[] a1, int[] a2) {
int[] res = new int[a1.length + a2.length];
int i = 0, j = 0;
while (i < a1.length && j < a2.length) {
res[i + j] = a1[i] < a2[j] ? a1[i++] : a2[j++];
}
while (i < a1.length) {
res[i + j] = a1[i++];
}
while (j < a2.length) {
res[i + j] = a2[j++];
}
return res;
}
public static int[] mergeSorted(int[] left, int[] right) {
System.out.println("merging " + Arrays.toString(left) + " and " + Arrays.toString(right));
int[] merged = new int[left.length + right.length];
int nextIndexLeft = 0;
int nextIndexRight = 0;
for (int i = 0; i < merged.length; i++) {
if (nextIndexLeft >= left.length) {
System.arraycopy(right, nextIndexRight, merged, i, right.length - nextIndexRight);
break;
}
if (nextIndexRight >= right.length) {
System.arraycopy(left, nextIndexLeft, merged, i, left.length - nextIndexLeft);
break;
}
if (left[nextIndexLeft] <= right[nextIndexRight]) {
merged[i] = left[nextIndexLeft];
nextIndexLeft++;
continue;
}
if (left[nextIndexLeft] > right[nextIndexRight]) {
merged[i] = right[nextIndexRight];
nextIndexRight++;
continue;
}
}
System.out.println("merged : " + Arrays.toString(merged));
return merged;
}
Just a small different from the original solution
To marge two sorted array in O(m+n) time complexity use below approach with one loop only.
m and n is length of first array and second array.
public class MargeSortedArray {
public static void main(String[] args) {
int[] array = new int[]{1,3,4,7};
int[] array2 = new int[]{2,5,6,8,12,45};
int[] newarry = margeToSortedArray(array, array2);
//newarray is marged array
}
// marge two sorted array with o(a+n) time complexity
public static int[] margeToSortedArray(int[] array, int[] array2) {
int newarrlen = array.length+array2.length;
int[] newarr = new int[newarrlen];
int pos1=0,pos2=0;
int len1=array.length, len2=array2.length;
for(int i =0;i<newarrlen;i++) {
if(pos1>=len1) {
newarr[i]=array2[pos2];
pos2++;
continue;
}
if(pos2>=len2) {
newarr[i]=array[pos1];
pos1++;
continue;
}
if(array[pos1]>array2[pos2]) {
newarr[i]=array2[pos2];
pos2++;
} else {
newarr[i]=array[pos1];
pos1++;
}
}
return newarr;
}
}
var arr1 = [2,10,20,30,100];
var arr2 = [2,4,5,6,7,8,9];
var j = 0;
var i =0;
var newArray = [];
for(var x=0;x< (arr1.length + arr2.length);x++){
if(arr1[i] >= arr2[j]){ //check if element arr2 is equal and less than arr1 element
newArray.push(arr2[j]);
j++;
}else if(arr1[i] < arr2[j]){ //check if element arr1 index value is less than arr2 element
newArray.push(arr1[i]);
i++;
}
else if(i == arr1.length || j < arr2.length){ // add remaining arr2 element
newArray.push(arr2[j]);
j++
}else{ // add remaining arr1 element
newArray.push(arr1[i]);
i++
}
}
console.log(newArray);
Since the question doesn't assume any specific language. Here is the solution in Python.
Assuming the arrays are already sorted.
Approach 1 - using numpy arrays:
import numpy
arr1 = numpy.asarray([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 15, 55])
arr2 = numpy.asarray([11, 32, 43, 45, 66, 76, 88])
array = numpy.concatenate((arr1,arr2), axis=0)
array.sort()
Approach 2 - Using list, assuming lists are sorted.
list_new = list1.extend(list2)
list_new.sort()
Here is my java implementation that remove duplicate.
public static int[] mergesort(int[] a, int[] b) {
int[] c = new int[a.length + b.length];
int i = 0, j = 0, k = 0, duplicateCount = 0;
while (i < a.length || j < b.length) {
if (i < a.length && j < b.length) {
if (a[i] == b[j]) {
c[k] = a[i];
i++;j++;duplicateCount++;
} else {
c[k] = a[i] < b[j] ? a[i++] : b[j++];
}
} else if (i < a.length) {
c[k] = a[i++];
} else if (j < a.length) {
c[k] = b[j++];
}
k++;
}
return Arrays.copyOf(c, c.length - duplicateCount);
}
import java.util.Arrays;
public class MergeTwoArrays {
static int[] arr1=new int[]{1,3,4,5,7,7,9,11,13,15,17,19};
static int[] arr2=new int[]{2,4,6,8,10,12,14,14,16,18,20,22};
public static void main(String[] args){
int FirstArrayLocation =0 ;
int SecondArrayLocation=0;
int[] mergeArr=new int[arr1.length + arr2.length];
for ( int i=0; i<= arr1.length + arr2.length; i++){
if (( FirstArrayLocation < arr1.length ) && (SecondArrayLocation < arr2.length)){
if ( arr1[FirstArrayLocation] <= arr2[SecondArrayLocation]){
mergeArr[i]=arr1[FirstArrayLocation];
FirstArrayLocation++;
}else{
mergeArr[i]=arr2[SecondArrayLocation];
SecondArrayLocation++;
}
}
else if(SecondArrayLocation < arr2.length){
mergeArr[i]=arr2[SecondArrayLocation];
SecondArrayLocation++;
}else if ( FirstArrayLocation < arr1.length ){
mergeArr[i]=arr1[FirstArrayLocation];
FirstArrayLocation++;
}
}
}
}

Categories

Resources