Ripple out integer array optimisation in Java - java

I am trying to write a function that will accept an array length, and return a "ripple out" array.
For example:
rippleOut(3) would return [0,1,0]
rippleOut(6) would return [0,1,2,2,1,0]
This is what I've got so far. It works, but I'm sure that there is a more efficient way to do it:
public int[] rippleOut(int size){
int[] output = new int[size];
int middle = 0;
boolean even = false;
if(size%2==0){
middle = (size/2-1);
even = true;
} else {
middle = (int)Math.floor(size/2);
}
for(int i = middle; i>0; i--){
output[i] = middle - (middle-i);
if (even){
output[middle+(middle - i+1)] = middle - (middle-i);
} else {
output[middle+(middle - i)] = middle - (middle-i);
}
}
return output;
}

This is a Java 8 version:
int size = 11;
int odd = (size % 2 == 0) ? 0 : 1;
int mid = (size / 2) - 1;
int[] output = IntStream.range(0, size - 1)
.map(i -> (i > mid) ? mid + (mid - i) + odd : i).toArray();
IntStream.of(output).forEach(System.out::print);

There is at least a simpler way to write it, I haven't compared the performance:
public static int[] rippleOut(int x) {
int[] r = new int[x];
// everything except the middle of an odd array
for (int i = 0; i < (x >> 1); i++) {
r[i] = i;
r[x - i - 1] = i;
}
// fix middle
if ((x & 1) == 1)
r[x >> 1] = x >> 1;
return r;
}
Feel free to replace the bitmath with "normal" math if you're more comfortable with that, it's not integral to the solution. I just like it this way, that's all.

Related

How can i fix array index out of bound of my java code?

Hey guys can anyone help me in my problem about array index out of bound in my java code. Below is my full code having a problem.
public static double calculateMedian(double[] arr) {
double[] sortedArr = sortarr(arr);
double median;
if (arr.length % 2 == 0) {
int indexA = (arr.length-1) / 2;
int indexB = (arr.length) / 2;
median = ((double) (sortedArr[indexA] + sortedArr[indexB])) / 2; // this code has a error in index out of bounds.
}
else {
int index = (sortedArr.length - 1) / 2;
median = sortedArr[ index ];
}
return median;
}
This is my sorting fucntion
public static double[] sortarr(double[] arr) {
boolean performedSwap = true;
double modeValue;
while(performedSwap) {
performedSwap = false;
for (int i=0; i < arr.length-1; i++) {
if (arr[i] > arr[i+1]) {
modeValue = arr[i];
arr[i] = arr[i+1];
arr[i+1] = modeValue;
performedSwap = true;
}
}
}
return arr;
}
if arr.length = 0 (empty array) your code try to take sortedArr[0] and you have this exception.
You are clearly passing an empty array.
Add an extra condition before checking for arr.length % 2 == 0 to see if arr.length == 0.
Not sure what you would want to return as the median in that case.
The only case where the error can happen is if your array is empty. The median for empty array is none since there is no value to begin with.
public static double calculateMedian(double[] arr) {
double[] sortedArr = sortarr(arr);
double median;
if (arr.length == 0) {
return ; // return nothing if it is an empty array
} else if (arr.length % 2 == 0) {
int indexA = (arr.length-1) / 2;
int indexB = (arr.length) / 2;
median = ((double) (sortedArr[indexA] + sortedArr[indexB])) / 2; // this code has a error in index out of bounds.
} else {
int index = (sortedArr.length - 1) / 2;
median = sortedArr[ index ];
}
return median;
}

NumberOfDiscIntersections overflow in codility test

In the codility test NumberOfDiscIntersections I am getting perf 100% and correctness 87% with the one test failing being
overflow
arithmetic overflow tests
got -1 expected 2
I can't see what is causing that given that I am using long which is 64-bit. And even if I can get it to 100% perf 100% correctness I am wondering if there is a better way to do this that is not as verbose in Java.
edit: figured out a much better way to do with with two arrays rather than a pair class
// you can also use imports, for example:
import java.util.*;
// you can use System.out.println for debugging purposes, e.g.
// System.out.println("this is a debug message");
class Solution {
public int solution(int[] A) {
int j = 0;
Pair[] arr = new Pair[A.length * 2];
for (int i = 0; i < A.length; i++) {
Pair s = new Pair(i - A[i], true);
arr[j] = s;
j++;
Pair e = new Pair(i + A[i], false);
arr[j] = e;
j++;
}
Arrays.sort(arr, new Pair(0, true));
long numIntersect = 0;
long currentCount = 0;
for (Pair p: arr) {
if (p.start) {
numIntersect += currentCount;
if (numIntersect > 10000000) {
return -1;
}
currentCount++;
} else {
currentCount--;
}
}
return (int) numIntersect;
}
static private class Pair implements Comparator<Pair> {
private long x;
private boolean start;
public Pair(long x, boolean start) {
this.x = x;
this.start = start;
}
public int compare(Pair p1, Pair p2) {
if (p1.x < p2.x) {
return -1;
} else if (p1.x > p2.x) {
return 1;
} else {
if (p1.start && p2.start == false) {
return -1;
} else if (p1.start == false && p2.start) {
return 1;
} else {
return 0;
}
}
}
}
}
Look at this line:
Pair s = new Pair(i + A[i], true);
This is equivalent with Pair s = new Pair((long)(i + A[i]) , true);
As i is integer, and A[i] is also integer, so this can cause overflow, as value in A[i] can go up to Integer.MAX_VALUE, and the cast to long happened after add operation is completed.
To fix:
Pair s = new Pair((long)i + (long)A[i], true);
Note: I have submitted with my fixed and got 100%
https://codility.com/demo/results/demoRRBY3Q-UXH/
My todays solution. O(N) time complexity. Simple assumption that number of availble pairs in next point of the table is difference between total open circle to that moment (circle) and circles that have been processed before. Maybe it's to simple :)
public int solution04(int[] A) {
final int N = A.length;
final int M = N + 2;
int[] left = new int[M]; // values of nb of "left" edges of the circles in that point
int[] sleft = new int[M]; // prefix sum of left[]
int il, ir; // index of the "left" and of the "right" edge of the circle
for (int i = 0; i < N; i++) { // counting left edges
il = tl(i, A);
left[il]++;
}
sleft[0] = left[0];
for (int i = 1; i < M; i++) {// counting prefix sums for future use
sleft[i]=sleft[i-1]+left[i];
}
int o, pairs, total_p = 0, total_used=0;
for (int i = 0; i < N; i++) { // counting pairs
ir = tr(i, A, M);
o = sleft[ir]; // nb of open till right edge
pairs = o -1 - total_used;
total_used++;
total_p += pairs;
}
if(total_p > 10000000){
total_p = -1;
}
return total_p;
}
int tl(int i, int[] A){
int tl = i - A[i]; // index of "begin" of the circle
if (tl < 0) {
tl = 0;
} else {
tl = i - A[i] + 1;
}
return tl;
}
int tr(int i, int[] A, int M){
int tr; // index of "end" of the circle
if (Integer.MAX_VALUE - i < A[i] || i + A[i] >= M - 1) {
tr = M - 1;
} else {
tr = i + A[i] + 1;
}
return tr;
}
My take on this, O(n):
public int solution(int[] A) {
int[] startPoints = new int[A.length];
int[] endPoints = new int[A.length];
int tempPoint;
int currOpenCircles = 0;
long pairs = 0;
//sum of starting and end points - how many circles open and close at each index?
for(int i = 0; i < A.length; i++){
tempPoint = i - A[i];
startPoints[tempPoint < 0 ? 0 : tempPoint]++;
tempPoint = i + A[i];
if(A[i] < A.length && tempPoint < A.length) //first prevents int overflow, second chooses correct point
endPoints[tempPoint]++;
}
//find all pairs of new circles (combinations), then make pairs with exiting circles (multiplication)
for(int i = 0; i < A.length; i++){
if(startPoints[i] >= 2)
pairs += (startPoints[i] * (startPoints[i] - 1)) / 2;
pairs += currOpenCircles * startPoints[i];
currOpenCircles += startPoints[i];
currOpenCircles -= endPoints[i];
if(pairs > 10000000)
return -1;
}
return (int) pairs;
}
The explanation to Helsing's solution part:
if(startPoints[i] >= 2) pairs += (startPoints[i] * (startPoints[i] - 1)) / 2;
is based on mathematical combinations formula:
Cn,m = n! / ((n-m)!.m!
for pairs, m=2 then:
Cn,2 = n! / ((n-2)!.2
Equal to:
Cn,2 = n.(n-1).(n-2)! / ((n-2)!.2
By simplification:
Cn,2 = n.(n-1) / 2
Not a very good performance, but using streams.
List<Long> list = IntStream.range(0, A.length).mapToObj(i -> Arrays.asList((long) i - A[i], (long) i + A[i]))
.sorted((o1, o2) -> {
int f = o1.get(0).compareTo(o2.get(0));
return f == 0 ? o1.get(1).compareTo(o2.get(1)) : f;
})
.collect(ArrayList<Long>::new,
(acc, val) -> {
if (acc.isEmpty()) {
acc.add(0l);
acc.add(val.get(1));
} else {
Iterator it = acc.iterator();
it.next();
while (it.hasNext()) {
long el = (long) it.next();
if (val.get(0) <= el) {
long count = acc.get(0);
acc.set(0, ++count);
} else {
it.remove();
}
}
acc.add(val.get(1));
}
},
ArrayList::addAll);
return (int) (list.isEmpty() ? 0 : list.get(0) > 10000000 ? -1 : list.get(0));
This one in Python passed all "Correctness tests" and failed all "Performance tests" due to O(n²), so I got 50% score. But it is very simple to understand. I just used the right radius (maximum) and checked if it was bigger or equal to the left radius (minimum) of the next circles. I also avoided to use sort and did not check twice the same circle. Later I will try to improve performance, but the problem here for me was the algorithm. I tried to find a very easy solution to help explain the concept. Maybe this will help someone.
def solution(A):
n = len(A)
cnt = 0
for j in range(1,n):
for i in range(n-j):
if(i+A[i]>=i+j-A[i+j]):
cnt+=1
if(cnt>1e7):
return -1
return cnt

Implementing a binary insertion sort using binary search in Java

I'm having trouble combining these two algorithms together. I've been asked to modify Binary Search to return the index that an element should be inserted into an array. I've been then asked to implement a Binary Insertion Sort that uses my Binary Search to sort an array of randomly generated ints.
My Binary Search works the way it's supposed to, returning the correct index whenever I test it alone. I wrote out Binary Insertion Sort to get a feel for how it works, and got that to work as well. As soon as I combine the two together, it breaks. I know I'm implementing them incorrectly together, but I'm not sure where my problem lays.
Here's what I've got:
public class Assignment3
{
public static void main(String[] args)
{
int[] binary = { 1, 7, 4, 9, 10, 2, 6, 12, 3, 8, 5 };
ModifiedBinaryInsertionSort(binary);
}
static int ModifiedBinarySearch(int[] theArray, int theElement)
{
int leftIndex = 0;
int rightIndex = theArray.length - 1;
int middleIndex = 0;
while(leftIndex <= rightIndex)
{
middleIndex = (leftIndex + rightIndex) / 2;
if (theElement == theArray[middleIndex])
return middleIndex;
else if (theElement < theArray[middleIndex])
rightIndex = middleIndex - 1;
else
leftIndex = middleIndex + 1;
}
return middleIndex - 1;
}
static void ModifiedBinaryInsertionSort(int[] theArray)
{
int i = 0;
int[] returnArray = new int[theArray.length + 1];
for(i = 0; i < theArray.length; i++)
{
returnArray[ModifiedBinarySearch(theArray, theArray[i])] = theArray[i];
}
for(i = 0; i < theArray.length; i++)
{
System.out.print(returnArray[i] + " ");
}
}
}
The return value I get for this when I run it is 1 0 0 0 0 2 0 0 3 5 12. Any suggestions?
UPDATE: updated ModifiedBinaryInsertionSort
static void ModifiedBinaryInsertionSort(int[] theArray)
{
int index = 0;
int element = 0;
int[] returnArray = new int[theArray.length];
for (int i = 1; i < theArray.lenght - 1; i++)
{
element = theArray[i];
index = ModifiedBinarySearch(theArray, 0, i, element);
returnArray[i] = element;
while (index >= 0 && theArray[index] > element)
{
theArray[index + 1] = theArray[index];
index = index - 1;
}
returnArray[index + 1] = element;
}
}
Here is my method to sort an array of integers using binary search.
It modifies the array that is passed as argument.
public static void binaryInsertionSort(int[] a) {
if (a.length < 2)
return;
for (int i = 1; i < a.length; i++) {
int lowIndex = 0;
int highIndex = i;
int b = a[i];
//while loop for binary search
while(lowIndex < highIndex) {
int middle = lowIndex + (highIndex - lowIndex)/2; //avoid int overflow
if (b >= a[middle]) {
lowIndex = middle+1;
}
else {
highIndex = middle;
}
}
//replace elements of array
System.arraycopy(a, lowIndex, a, lowIndex+1, i-lowIndex);
a[lowIndex] = b;
}
}
How an insertion sort works is, it creates a new empty array B and, for each element in the unsorted array A, it binary searches into the section of B that has been built so far (From left to right), shifts all elements to the right of the location in B it choose one right and inserts the element in. So you are building up an at-all-times sorted array in B until it is the full size of B and contains everything in A.
Two things:
One, the binary search should be able to take an int startOfArray and an int endOfArray, and it will only binary search between those two points. This allows you to make it consider only the part of array B that is actually the sorted array.
Two, before inserting, you must move all elements one to the right before inserting into the gap you've made.
I realize this is old, but the answer to the question is that, perhaps a little unintuitively, "Middleindex - 1" will not be your insertion index in all cases.
If you run through a few cases on paper the problem should become apparent.
I have an extension method that solves this problem. To apply it to your situation, you would iterate through the existing list, inserting into an empty starting list.
public static void BinaryInsert<TItem, TKey>(this IList<TItem> list, TItem item, Func<TItem, TKey> sortfFunc)
where TKey : IComparable
{
if (list == null)
throw new ArgumentNullException("list");
int min = 0;
int max = list.Count - 1;
int index = 0;
TKey insertKey = sortfFunc(item);
while (min <= max)
{
index = (max + min) >> 1;
TItem value = list[index];
TKey compKey = sortfFunc(value);
int result = compKey.CompareTo(insertKey);
if (result == 0)
break;
if (result > 0)
max = index - 1;
else
min = index + 1;
}
if (index <= 0)
index = 0;
else if (index >= list.Count)
index = list.Count;
else
if (sortfFunc(list[index]).CompareTo(insertKey) < 0)
++index;
list.Insert(index, item);
}
Dude, I think you have some serious problem with your code. Unfortunately, you are missing the fruit (logic) of this algorithm. Your divine goal here is to get the index first, insertion is a cake walk, but index needs some sweat. Please don't see this algorithm unless you gave your best and desperate for it. Never give up, you already know the logic, your goal is to find it in you. Please let me know for any mistakes, discrepancies etc. Happy coding!!
public class Insertion {
private int[] a;
int n;
int c;
public Insertion()
{
a = new int[10];
n=0;
}
int find(int key)
{
int lowerbound = 0;
int upperbound = n-1;
while(true)
{
c = (lowerbound + upperbound)/2;
if(n==0)
return 0;
if(lowerbound>=upperbound)
{
if(a[c]<key)
return c++;
else
return c;
}
if(a[c]>key && a[c-1]<key)
return c;
else if (a[c]<key && a[c+1]>key)
return c++;
else
{
if(a[c]>key)
upperbound = c-1;
else
lowerbound = c+1;
}
}
}
void insert(int key)
{
find(key);
for(int k=n;k>c;k--)
{
a[k]=a[k-1];
}
a[c]=key;
n++;
}
void display()
{
for(int i=0;i<10;i++)
{
System.out.println(a[i]);
}
}
public static void main(String[] args)
{
Insertion i=new Insertion();
i.insert(56);
i.insert(1);
i.insert(78);
i.insert(3);
i.insert(4);
i.insert(200);
i.insert(6);
i.insert(7);
i.insert(1000);
i.insert(9);
i.display();
}
}

Is this a proper implementation of mergesort?

I'm worried that the creation of 3 arrays for every recursion step might take up too much space, but I really couldn't figure out another way of doing it. Please tell me whatever is wrong with it.
public static int[] split(int [] vector){
if(vector.length <= 1 || vector == null)
return vector;
int len = vector.length;
int[] list1 = new int[len / 2];
// If the number of elements is odd the second list will be bigger
int[] list2 = new int[len / 2 + (len % 2)];
// Here we assign the elements to 2 separate lists
for(int x = 0; x < len / 2; x++)
list1[x] = vector[x];
for(int j = 0, i = len / 2; j < list2.length; i++, j++)
list2[j]=vector[i];
// Apply the recursion, this will eventually order the lists
list1 = split(list1);
list2 = split(list2);
// Here we take the 2 ordered lists and merge them into 1
int i = 0, a = 0, b = 0;
int[] listfinal = new int[len];
while(i < len){
if(a >= list1.length){
listfinal[i] = list2[b];
b++;
} else if(b >= list2.length){
listfinal[i] = list1[a];
a++;
} else if(list1[a] <= list2[b]){
listfinal[i] = list1[a];
a++;
} else if(list1[a] > list2[b]){
listfinal[i] = list2[b];
b++;
}
i++;
}
return listfinal; // Return the merged and ordered list
}
You shouldn't need to create more than one temporary array to do mergesort. What you're doing wrong is copying the arrays to pass to the recursive invocation; you should instead pass the original array.
It may be informative to look at the implementation of mergesort in the JDK - look on line 1146 of Arrays.java.
Here is code that allocates a single array equal to the input size at the top level and re-uses it for all the recursion. On a million integers, this takes about 300 ms on my machine and the Java library sort takes 230 ms. Okay for no tuning effort, I guess...
// Sort the elements of a between lo and hi inclusive.
private static void sortImpl(int [] a, int lo, int hi, int [] tmp) {
if (hi <= lo) return;
// Recur on sublists.
int mid = (hi + lo) / 2;
sortImpl(a, lo, mid, tmp);
sortImpl(a, mid + 1, hi, tmp);
// Move past items already in the right place.
int t1 = lo;
while (a[t1] < a[mid + 1]) t1++;
// Merge sublists into result.
int p1 = t1;
int p2 = mid + 1;
int i = t1;
System.arraycopy(a, t1, tmp, t1, mid - t1 + 1);
while (p1 <= mid)
a[i++] = (p2 > hi || tmp[p1] < a[p2]) ? tmp[p1++] : a[p2++];
}
public static void sort(int [] a) {
sortImpl(a, 0, a.length - 1, new int[a.length]);
}

Java decimal to binary int array

For this exercise I'm making I want a decimal < 4096 to be written in binary form in an int array.
So for example, 4 would be {0,0,0,0,0,0,0,0,0,1,0,0}. I need this for (nearly) all integers up to 4096, so I've written this piece of code:
for(int k=0; k<4096; k++){
int[] myNumber = { (k / 2048) % 2, (k / 1024) % 2, (k / 512) % 2, (k / 256) % 2, (k / 128) % 2, (k / 64) % 2, (k / 32) % 2, (k / 16) % 2, (k / 8) % 2, (k / 4) % 2, (k / 2) % 2, (k / 1) % 2 }
/* Some processing */
}
This looks kind of ugly, so that's why I'm curious to find out if there is a more elegant way of achieving this?
For the interested reader:
I chose for the array approach of storing the binary numbers, because I need to perform some shifting and addition modulo 2. I'm using an LFSR, and this is my implementation for that:
public class LFSR {
private int[] polynomial;
public LFSR(int[] polynomial) {
this.polynomial = polynomial;
}
public int[] shiftLeft(int[] input) {
int[] result = new int[input.length];
int out = input[0];
result[input.length - 1] = out;
for (int i = input.length - 1; i > 0; i--) {
result[i - 1] = (input[i] + polynomial[i - 1] * out) % 2;
}
return result;
}
}
Any suggestions?
Some pseudo code:
While (int i = 0; i < 12; i++) {
bitarray[i] = numericalValue & 0x1;
numericalValue = numericalValue >> 1;
}
So, shifting right by one bit is division by 2, and ANDing with 1 always leaves you only with the lowest bit which is what you want.
One quick suggestion would be to switch to a byte array instead of an int array, simply to save space, as they will only be 'bits'.
With regards to improving the elegance of your solution, it is perhaps easier to use subcomputations:
int[] intToBinaryArray(int dec){
int[] res = int[12]
for(int i =0; i < 12; i++)
bitarray[i] = numericalValue & 0x1; //grab first bit only
dec /= 2;
}
return res;
}
String s = Integer.toBinaryString(int value);
Now convert the String to int[]
int[] intArray = new int[s.length()];
for (int i = 0; i < s.length(); i++) {
intArray[i] = Character.digit(s.charAt(i), 10);
}
This is somewhat shorter ;)
int[] bits = new int[13];
String bin = Integer.toBinaryString(8192 + value);
for(int i = 1; i < bin.length(); i++) {
bits[i-1] = bin.charAt(i)-'0';
}
"Elegance" is in the eye of the beholder, but I'd start by creating a method to avoid repetition and improve clarity:
int[] myNumber = { getBit(k, 12), getBit(k, 11), ... };
I personally feel this is the "most elegant" way to get a particular bit:
int getBit(int v, int i)
{
return v >> i & 1;
}
Then you have to decide whether you want to keep repeating yourself with the calls to getBit or whether you'd rather just use a single while or for loop to populate the whole array. You'd think it'd be quicker the way you've got it written, but there's good chance the JIT compiler automatically unrolls your loop for you if you use a loop like Jochen suggests.
Since this particular operation is entirely self contained, you might even want to create a special method for it:
int[] getBits(int v, int num)
{
int[] arr = new int[num];
for(int i=0; i<num; i++) {
arr[i] = getBit(v, num - i - 1);
}
return arr;
}
That makes it easier to unit test, and you can reuse it in a variety of situations.
public int[] toBin (int num)
{
int[] ret = new int[8];
for (int i = 7, p = 0; i>=0; i--, p++)
{
ret[i] = (num/2**p) % 2;
}
return ret;
}
You could use the bit shift operator together withbthe bitwise AND operator as follows. Note bitCount - i - 1 is needed to get the high bit first.
final int bitCount =12; // Increase to support greater than 4095
int[] number = new int[bitCount];
for( int i = 0; i < bitCount; i++ )
{
number[i] = ( k >>> ( bitCount - i - 1 ) ) & 1;
}

Categories

Resources