Related
My condition is not outputting the right numbers, the list is not changed trough the loop, this is my condition.
if (j + 1 <= length)
{
insertionSort(arrayIn, indexIn + 1);
}
}
The condition for the recursive call:
if (j + 1 <= length)
is wrong.
You should make the recursive call as long as indexIn is smaller than the last index of the array:
if (indexIn < length - 1) {
insertionSort(arrayIn, indexIn + 1);
}
The rest of your code is fine.
You could try this:
public static void insertionSort(int arrayIn[], int indexIn) {
if (indexIn <= 1)
return;
insertionSort(arrayIn, indexIn - 1);
int last = arrayIn[indexIn - 1];
int j = indexIn - 2;
while (j >= 0 && arrayIn[j] > last) {
arrayIn[j + 1] = arrayIn[j];
j--;
}
arrayIn[j + 1] = last;
}
public static void main(String[] args){
int[] array = {1, 3, 2, 4};
insertionSort(array, array.length);
for (int i = 0; i < array.length; i++){
System.out.print(array[i] + " ");
}
}
I could a ArrayIndexOutOfBound operation, in your code,
Instead of,
if (j + 1 <= length)
{
insertionSort(arrayIn, indexIn + 1);
}
Use this,
if (j + 1 < length)
{
insertionSort(arrayIn, indexIn + 1);
}
And you have print your content of your array too,
public static void main(String[] args) {
int[] arr = new int[]{2, 3, 4, 1, 5};
insertionSort(arr, 0);
for(int i : arr)
{
System.out.print(i + " ");
}
}
Output:
1 2 3 4 5
I'm studying the 3 Sum to implement it on my own, and came across the following implementation with the rules:
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4},
A solution set is:
(-1, 0, 1)
(-1, -1, 2)
And implementation (sorts the array, iterates through the list, and uses another two pointers to approach the target):
import java.util.*;
public class ThreeSum {
List<List<Integer>> threeSum(int[] num) {
Arrays.sort(num);
List<List<Integer>> res = new LinkedList<>();
for (int i=0; i<num.length-2; i++) {
if (i==0 || (i>0 && num[i] != num[i-1])) { //HERE
int lo = i+1;
int hi = num.length-1;
int sum = 0 - num[i];
while (lo < hi) {
if (num[lo] + num[hi] == sum) {
res.add(Arrays.asList(num[i], num[lo], num[hi]));
while (lo < hi && num[lo] == num[lo+1]) lo++; //HERE
while (lo < hi && num[hi] == num[hi-1]) hi--; //HERE
lo++; hi--;
} else if (num[lo] + num[hi] < sum) lo++;
else hi--;
}
}
}
return res;
}
//Driver
public static void main(String args[]) {
ThreeSum ts = new ThreeSum();
int[] sum = {-1, 0, 1, 2, -1, -4};
System.out.println(ts.threeSum(sum));
}
}
And my question is (located where commented: //HERE), what's the reason for checking num[i] != num[i-1], num[lo] == num[lo+1], and num[hi] == num[hi-1]? Supposedly they are supposed to skip the same result, but what does that mean? Examples would really help.
Thank you in advance and will accept answer/up vote.
Imagine you have {-1,-1,0,1,2,4} and considering triplet num[0], num[2], num[3] (-1,0,1).
lo=0 here. To exclude triplet num[1], num[2], num[3] with the same values, we should increment lo and pass over duplicate
This will prevent the list to have duplicate triplet.
For example, with you test :
int[] sum = {-1, 0, 1, 2, -1, -4};
will be sorted like :
sum = {-4, -1, -1, 0, 1, 2};
You see that you have -1 twice. Without these test, you would test twice if -1 = 0 + 1. This is not usefull so the algo simply search the next different value.
You could remove duplicate in the sorted List to prevent these test.
Thanks to MBo, we can't remove duplicate since we can have triplet with same value (but with different index)
All the three sentences is used to avoid the duplicate output.
Consider a sorted list {-2, -2 , 1, 1}
If there is no checking for num[i] != num[i-1], the output of the program would be(-2, 1, 1)and(-2, 1, 1), which are two duplicate triplets.
The checking for num[lo] != num[lo + 1]and num[hi] != num[hi - 1] are for the same reason.
Consider a sorted list
{-2,-1,-1,0,3}
If there is no checking for num[lo], you will get (-2,-1,3) and (-2,-1,3) as the output.
Still, I want to recommend a better solution for this problem. You can numerate the sum of two numbers in the list and find the 3rd number by hash or binary search. It will helps you to gain a O(n^2logn) time complexity rather than O(n^3). (I was wrong, the time complexity of this algorithm is O(n^2), sorry for that.)
Following program finds pairs of three integer with O(N*2)
Sort the input Array
and iterate each element in for loop and check for sum in program which is developed for Two sum.
Two sum in linear time after sorting ->
https://stackoverflow.com/a/49650614/4723446
public class ThreeSum {
private static int countThreeSum(int[] numbers) {
int count = 0;
for (int i = 0; i < numbers.length; i++) {
int front = 0, rear = numbers.length - 1;
while (front < rear) {
if (numbers[front] + numbers[rear] + numbers[i] == 0) {
System.out.printf(String.format("Front : {%d} Rear : {%d} I : {%d} \n", numbers[front],
numbers[rear], numbers[i]));
front++;
rear--;
count++;
} else {
if (Math.abs(numbers[front]) > Math.abs(numbers[rear])) {
front++;
} else {
rear--;
}
}
}
}
return count;
}
public static void main(String[] args) {
int[] numbers = { 1, 3, 5, 7, 12, 16, 19, 15, 11, 8, -1, -3, -7, -8, -11, -17, -15 };
Arrays.sort(numbers);
System.out.println(countThreeSum(numbers));
}
}
It's worked with any NSum (3Sum, 4Sum, 5Sum, ...) and quite fast.
public class ThreeSum {
private static final int RANDOM_RANGE = 20;
private Integer array[];
private Integer arrayIndex[];
private int result[];
private int bagLength;
private int resultIndex = 0;
private void generateData(int size) {
array = new Integer[size];
Random random = new Random();
for (int i = 0; i < size; i++) {
array[i] = random.nextInt(RANDOM_RANGE) - (RANDOM_RANGE/2);
}
}
private void markArrayIndex(int size) {
arrayIndex = new Integer[size];
for (int i = 0; i < size; i++) {
arrayIndex[i] = i;
}
}
private void prepareBeforeCalculate(int size, int sumExpected, int bagLength) {
this.bagLength = bagLength;
result = new int[bagLength];
generateData(size);
markArrayIndex(size);
}
void calculate(int size, int sumExpected, int bagLength) {
prepareBeforeCalculate(size, sumExpected, bagLength);
Arrays.sort(arrayIndex, (l, r) -> array[l].compareTo(array[r]));
System.out.println(Arrays.toString(array));
long startAt = System.currentTimeMillis();
if (sumExpected > 0) findLeft(sumExpected, 0, 0, array.length);
else findRight(sumExpected, 0, 0 - 1, array.length - 1);
System.out.println("Calculating in " + ((System.currentTimeMillis() - startAt) / 1000));
}
private void findLeft(int total, int indexBag, int left, int right) {
while (left < array.length && array[arrayIndex[left]] < 0 && indexBag < bagLength) {
navigating(total, arrayIndex[left], indexBag, left, right);
left++;
}
}
private void findRight(int total, int indexBag, int left, int right) {
while (right >= 0 && array[arrayIndex[right]] >= 0 && indexBag < bagLength) {
navigating(total, arrayIndex[right], indexBag, left, right);
right--;
}
}
private void navigating(int total, int index, int indexBag, int left, int right) {
result[indexBag] = index;
total += array[index];
if (total == 0 && indexBag == bagLength - 1) {
System.out.println(String.format("R[%d] %s", resultIndex++, toResultString()));
return;
}
if (total > 0) findLeft(total, indexBag + 1, left + 1, right);
else findRight(total, indexBag + 1, left, right - 1);
}
private String toResultString() {
int [] copyResult = Arrays.copyOf(result, result.length);
Arrays.sort(copyResult);
int iMax = copyResult.length - 1;
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(array[copyResult[i]]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
}
public class ThreeSumTest {
#Test
public void test() {
ThreeSum test = new ThreeSum();
test.calculate(100, 0, 3);
Assert.assertTrue(true);
}
}
I'm trying to make the merge sort to use only (n/2 + 1) extra space and still O(n log n) time. This is my homework.
The original quesetion:
Write the non-recursive version of merge sort. Your program should run
in O(n log n) time and use n/2 + O(1) extra spaces.
The program will split an array in to two like normal merge sort. The left part will be in another array, which is ceil(n/2) long, so it will fit the requirement.
The right part will be in the original array. So it will be half in-place sorting
Sorry, I don't know how to explain further.
I think this is basically correct. But I kept on facing OutOfBounds error.
I know the code is quite long and messy. But can anyone help me about that?
I spent about 5 hours to implement this. Please help me.
package comp2011.lec6;
import java.util.Arrays;
public class MergeSort {
public static void printArr(int[] arr){
for(int i = 0; i < arr.length; i++){
System.out.printf("%d ", arr[i]);
}
}
public static void mergeSort(int[] arr){
if(arr.length<2) {
return;
}
int n, lBegin, rBegin;
n = 1;
int[] leftArr = new int[arr.length - (arr.length/2)];
while(n<arr.length) {
lBegin = 0;
rBegin = n;
while(rBegin + n <= arr.length) {
mergeArrays(arr, lBegin, lBegin+n, rBegin, rBegin+n, leftArr);
lBegin = rBegin+n;
rBegin = lBegin+n;
}
if(rBegin < arr.length) {
mergeArrays(arr, lBegin, lBegin+n, rBegin, arr.length, leftArr);
}
n = n*2;
}
}
public static void mergeArrays(int[] array, int startL, int stopL, int startR, int stopR, int[] leftArr) {
// int[] right = new int[stopR - startR + 1];
// int[] left = new int[stopL - startL + 1];
// for(int i = 0, k = startR; i < (right.length - 1); ++i, ++k) {
// right[i] = array[k];
// }
System.out.println("==============");
System.out.println("stopL: " + stopL +" startL: " + startL);
for(int i = 0, k = startL; i <= (stopL - startL); ++i, ++k) {
System.out.println(leftArr[i]);
leftArr[i] = array[k];
}
// right[right.length-1] = Integer.MAX_VALUE;
leftArr[stopL - startL] = Integer.MAX_VALUE;
System.out.println("leftArr: " + Arrays.toString(leftArr));
System.out.println("RightArr: " + Arrays.toString(Arrays.copyOfRange(array, startR, stopR)));
System.out.println("before: " + Arrays.toString(array));
// for(int k = startL, m = 0, n = startR; k < stopR; ++k) {
System.out.println("StartL: " + startL + " StartR: " + stopR);
for(int k = startL, m = 0, n = startR; ( (k < stopR) ); ++k) {
System.out.println("k: " + k);
System.out.println("Left: " + leftArr[m]);
System.out.println("Right: " + array[n]);
System.out.println("Array[k] before: " + array[k]);
// if(leftArr[m] == Integer.MAX_VALUE){
// System.out.println("YES");
// }
if( (leftArr[m] <= array[n]) || (n >= stopR) ) {
System.out.println("Left is smaller than right");
array[k] = leftArr[m];
m++;
}
else {
System.out.println("Right is smaller than left");
array[k] = array[n];
System.out.println("right: " + array[k]);
n++;
}
System.out.println("Array[k] after: " + array[k]+"\n");
}
System.out.println("after " + Arrays.toString(array));
}
public static void main(String[] args) {
int[] array = new int[] { 5, 2, 4, 12, 2, 10, 13, 1, 7 };
mergeSort(array);
printArr(array);
}
}
Below code I have written by following the logic from Median of two sorted arrays (method - 2)
You can even see the code at Ideone.com
class MedianOfTwoArrays {
public static void main(String[] args) {
// Note: These are sorted arrays and are of equal length.
int[] array1 = {1, 12, 15, 26, 38};
int[] array2 = {2, 13, 17, 30, 45};
int median = getMedianOfTwoArrays(array1, array2);
System.out.println(median);
}
static int getMedianOfTwoArrays(int[] array1, int[] array2) {
int index1 = array1.length/2;
int index2 = array2.length/2;
int m1 = array1[index1];
int m2 = array2[index2];
if(m1 == m2) {
return m1;
} else {
return findMedian(array1, array2, 0, array1.length - 1, 0, array2.length - 1);
}
}
static int findMedian(int[] array1,
int[] array2,
int low1,
int high1,
int low2,
int high2) {
if((high1 - low1 + 1) == 2 && (high2 - low2 + 1) == 2) {
return (Math.max(array1[low1], array2[low2]) + Math.min(array1[high1], array2[high2]))/2;
}
int mid1 = (low1 + high1)/2;
int mid2 = (low2 + high2)/2;
int m1 = array1[mid1];
int m2 = array2[mid2];
int low1_t = 0;
int high1_t = 0;
int low2_t = 0;
int high2_t = 0;
if(m1 == m2) {
return m1;
} else if(m1 > m2) {
low1_t = low1;
high1_t = mid1;
low2_t = mid2;
high2_t = high2;
return findMedian(array1, array2, low1_t, high1_t, low2_t, high2_t);
} else {
low1_t = mid1;
high1_t = high1;
low2_t = low2;
high2_t = mid2;
return findMedian(array1, array2, low1_t, high1_t, low2_t, high2_t);
}
}
}
It does not work for input arrays like,
int[] array1 = {1, 5, 17, 20}; // median is 10
int[] array2 = {4, 8, 13, 19};
int[] array1 = {1, 3, 5, 7, 9, 11}; // median is 6
int[] array2 = {2, 4, 6, 8, 10, 12};
The problem as per my analysis is, the termination condition. Some how the logic suggessted from geeksforgeeks seems to be having some issue with the termination condition.
(Math.max(array1[low1], array2[low2]) + Math.min(array1[high1], array2[high2]))/2;
But I could not able to solve it and make it work for the above inputs.
Can someone please look into this issue and let me know where am I making mistake?
Your main error is that when you do plain int mid1 = (low1 + high1)/2; your mid1 is always shifted to the left, and then you assign mid1 without taking this shift into account, therefore each nested comparison compares elements of arrays that are shifted left from the intended position, and since median of an array of length 2n is always a[n-1]+a[n]/2, you are comparing wrong elements of arrays after the first performed comparison. You seemingly incorrently implemented this block of Method 2's code:
if (n % 2 == 0)
return getMedian(ar1 + n/2 - 1, ar2, n - n/2 +1);
else
return getMedian(ar1 + n/2, ar2, n - n/2);
In fact, the simple assert (high2-low2==high1-low1) at the entrance to findMedian() would alert you of incorrect logic, since with arrays of size 4 the second entrance yields unequal array sizes. The exit condition is pretty fine, as it's directly copied from Method 2's code. Therefore, you need to change the block of assigning low1_t and others to the following:
assert (high2-low2==high1-low1); // sanity check
int n=high1-low1+1; // "n" from logic
int m1 = median(array1,low1,high1);
int m2 = median(array2,low2,high2);
int low1_t = low1;
int high1_t = high1;
int low2_t = low2;
int high2_t = high2;
if(m1 == m2) {
return m1;
} else if(m1 > m2) {
if (n % 2 == 0) {
high1_t = high1-n/2+1;
low2_t = low2+n/2-1;
} else {
high1_t = high1-n/2;
low2_t = low2+n/2;
}
} else {
if (n % 2 == 0) {
low1_t = low1+n/2-1;
high2_t = high2-n/2+1;
} else {
low1_t = low1+n/2;
high2_t = high2-n/2;
}
}
return findMedian(array1, array2, low1_t, high1_t, low2_t, high2_t);
And add function median like this:
static int median(int[] arr, int low,int hig)
{
if ((low+hig)%2 == 0) return arr[(low+hig)/2];
int mid=(low+hig)/2;
return (arr[mid]+ arr[mid-1])/2;
}
Complete example (alter arrays as necessary): http://ideone.com/zY30Vg
This is a working code and it should solve your problem :-
public static void main(String[] args)
{
int[] ar1 = {1, 3, 5, 7, 9, 11};
int[] ar2 = {2, 4, 6, 8, 10, 12};
System.out.println((int) findMedianSortedArrays(ar1,ar2));
}
public static double findMedianSortedArrays(int A[], int B[]) {
int m = A.length;
int n = B.length;
if ((m + n) % 2 != 0) // odd
return (double) findKth(A, B, (m + n) / 2, 0, m - 1, 0, n - 1);
else { // even
return (findKth(A, B, (m + n) / 2, 0, m - 1, 0, n - 1)
+ findKth(A, B, (m + n) / 2 - 1, 0, m - 1, 0, n - 1)) * 0.5;
}
}
public static int findKth(int A[], int B[], int k,
int aStart, int aEnd, int bStart, int bEnd) {
int aLen = aEnd - aStart + 1;
int bLen = bEnd - bStart + 1;
// Handle special cases
if (aLen == 0)
return B[bStart + k];
if (bLen == 0)
return A[aStart + k];
if (k == 0)
return A[aStart] < B[bStart] ? A[aStart] : B[bStart];
int aMid = aLen * k / (aLen + bLen); // a's middle count
int bMid = k - aMid - 1; // b's middle count
// make aMid and bMid to be array index
aMid = aMid + aStart;
bMid = bMid + bStart;
if (A[aMid] > B[bMid]) {
k = k - (bMid - bStart + 1);
aEnd = aMid;
bStart = bMid + 1;
} else {
k = k - (aMid - aStart + 1);
bEnd = bMid;
aStart = aMid + 1;
}
return findKth(A, B, k, aStart, aEnd, bStart, bEnd);
}
I am fairly new to the concept of a binary search, and am trying to write a program that does this in Java for personal practice. I understand the concept of this well, but my code is not working.
There is a run-time exception happening in my code that just caused Eclipse, and then my computer, to crash... there are no compile-time errors here though.
Here is what I have so far:
public class BinarySearch
{
// instance variables
int[] arr;
int iterations;
// constructor
public BinarySearch(int[] arr)
{
this.arr = arr;
iterations = 0;
}
// instance method
public int findTarget(int targ, int[] sorted)
{
int firstIndex = 1;
int lastIndex = sorted.length;
int middleIndex = (firstIndex + lastIndex) / 2;
int result = sorted[middleIndex - 1];
while(result != targ)
{
if(result > targ)
{
firstIndex = middleIndex + 1;
middleIndex = (firstIndex + lastIndex) / 2;
result = sorted[middleIndex - 1];
iterations++;
}
else
{
lastIndex = middleIndex + 1;
middleIndex = (firstIndex + lastIndex) / 2;
result = sorted[middleIndex - 1];
iterations++;
}
}
return result;
}
// main method
public static void main(String[] args)
{
int[] sortedArr = new int[]
{
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29
};
BinarySearch obj = new BinarySearch(sortedArr);
int target = sortedArr[8];
int result = obj.findTarget(target, sortedArr);
System.out.println("The original target was -- " + target + ".\n" +
"The result found was -- " + result + ".\n" +
"This took " + obj.iterations + " iterations to find.");
} // end of main method
} // end of class BinarySearch
In Java, array indexing is zero-based. That is, the valid range of indexes is 0 up to, but not including, the array length. You are indexing from 1 to the array length. Try replacing this:
int firstIndex = 1;
int lastIndex = sorted.length;
with:
int firstIndex = 0;
int lastIndex = sorted.length - 1;
Also, as #Daniel's points out in his answer, in the case when you update lastIndex, the update should be to middleIndex - 1 (instead of to middleIndex + 1 as you have it now).
int result = sorted[middleIndex - 1];
should be
int result = sorted[middleIndex];
If lastIndex = 1, you try to access sorted[-1].
And
lastIndex = middleIndex + 1;
should be
lastIndex = middleIndex - 1;
or you may try to access past the end of sorted.
And, included for completeness, as Ted Hopp spotted, you should start with
firstIndex = 0;
lastIndex = sorted.length-1;
since array indices are 0-based.
The while loop in your method findTarget() is running infinitely. So I am guessing that the error you get at run time should be about memory related as it keeps running for ever.
would you consider some changes in your method findTarget()? If yes, try the sample below:
int firstIndex = 0;
int lastIndex = sorted.length-1;
while (firstIndex <= lastIndex) {
middleIndex = (firstIndex + lastIndex) / 2;
if (sorted[middleIndex] == targ) {
return middleIndex;
} else if (sorted[middleIndex] < targ) {
iterations++;
firstIndex = middleIndex + 1;
} else {
iterations++;
lastIndex = middleIndex - 1;
}
}
return -1;
Not only was my index logic off (as Ted and Daniel have pointed out above), but also the code block within the if statement should be switched with that of the else.
Here is the corrected code:
public class BinarySearch
{
// instance variables
int[] arr;
int iterations;
// constructor
public BinarySearch(int[] arr)
{
this.arr = arr;
iterations = 0;
}
// instance method
public int findTarget(int targ, int[] sorted)
{
int firstIndex = 0;
int lastIndex = sorted.length - 1;
int middleIndex = (firstIndex + lastIndex) / 2;
int result = sorted[middleIndex];
iterations++;
while(result != targ)
{
if(result > targ)
{
lastIndex = middleIndex - 1;
middleIndex = (firstIndex + lastIndex) / 2;
result = sorted[middleIndex];
iterations++;
}
else
{
firstIndex = middleIndex + 1;
middleIndex = (firstIndex + lastIndex) / 2;
result = sorted[middleIndex];
iterations++;
}
}
return result;
}
// main method
public static void main(String[] args)
{
int[] sortedArr = new int[]
{
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29
};
BinarySearch obj = new BinarySearch(sortedArr);
int target = sortedArr[8];
int result = obj.findTarget(target, sortedArr);
System.out.println("The original target was -- " + target + ".\n" +
"The result found was -- " + result + ".\n" +
"This took " + obj.iterations + " iterations to find.");
} // end of main method
} // end of class BinarySearch