Getting all posssible array index positions in an efficient way - java

Hi i want to find a way to find all possible index positions in an arbitrary size and arbitrary number of dimension size array. For example:
int [][][] myArray = new int [2][3][2]
i would then want all possible array index positions so the output would be something like:
0,0,0
1,0,0
0,1,0
0,2,0
and so on, so basically all positions of the array, and a way which is somewhat more efficient than having lots and lots of embedded loops.

multi-dimensional arrays are syntax sugar, they are physically located in single-dimension memory:
so, you can try something like that:
final int dim1 = 2;
final int dim2 = 3;
final int dim3 = 4;
final int[][][] myArray = new int[dim1][dim2][dim3];
for (long i = 0; i < ((long) dim1 * dim2 * dim3); i++) {
long idx = i;
final int i3 = (int) (idx % dim3);
idx /= dim3;
final int i2 = (int) (idx % dim2);
idx /= dim2;
final int i1 = (int) idx;
System.out.println(i1 + "," + i2 + "," + i3);
}
note: this code uses % and / operators which are quite slow, but if your dimensions are power of 2, you can replace it with & and >>> which could run faster neither nested loops
another variant:
final int dim1 = 2;
final int dim2 = 3;
final int dim3 = 4;
final int[][][] myArray = new int[dim1][dim2][dim3];
int i1 = 0;
int i2 = 0;
int i3 = 0;
for (long i = 0; i < ((long) dim1 * dim2 * dim3); i++) {
System.out.println(i1 + "," + i2 + "," + i3);
i3++;
if (i3 == dim3) {
i3 = 0;
i2++;
if (i2 == dim2) {
i2 = 0;
i1++;
}
}
}
it could work faster, but it has branch inside loop, so its better to benchmark both variants

I would favour an approach like this. The advantage of using a custom implementation of List like this is that you can represent all possible index combinations without having to store them all in memory simultaneously.
public static void main(String[] args) {
List<List<Integer>> indices = indices(2, 3);
for (List<Integer> list : indices)
System.out.println(list);
}
public static List<List<Integer>> indices(final int... dimensions) {
int s = 1;
for (int a : dimensions)
s *= a;
final int size = s;
return new AbstractList<List<Integer>>() {
#Override
public int size() {
return size;
}
#Override
public List<Integer> get(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException();
List<Integer> temp = new ArrayList<>();
for (int d : dimensions) {
temp.add(index % d);
index /= d;
}
return Collections.unmodifiableList(temp);
}
};
}

Related

Trouble with Prime connection

The problem below was given in one of my exams and was asked to solve the following problem using Java only.
The problem is, I got stuck in the part where the program is supposed to return the given non-negative integer as an array of digits. Can anyone provide a solution to this?
Thanks in advance.
Two positive numbers A and B are said to be connected (denoted by "A ↔ B") if one of these conditions holds:
(1) A and B have the same length and differ in exactly one digit; for example, 123 ↔ 173.
(2) Adding one digit to the left of A (or B) makes B (or A); for example, 23 ↔ 223 and 123 ↔ 23.
We call a prime P a 2's relative if there exists a chain of connected primes between 2 and P and no prime in the chain exceeds P.
For example, 127 is a 2's relative. One of the possible chains is shown below:
2 ↔ 3 ↔ 13 ↔ 113 ↔ 103 ↔ 107 ↔ 127
However, 11 and 103 are not 2's relatives.
Let F(N) be the sum of the primes ≤ N which are not 2's relatives.
We can verify that F(103) = 431 and F(104) = 78728.
Find F(107).
Edited: my part
I am sorry I don't carbon copy remember my solution as I don't have my results given to me. But just for the sake of this question, I think the part where it was supposed to return non-negative number, I had something like this -
private static int[] toDigits(int n) {
if (n < 0)
throw new IllegalArgumentException();
int[] temp = new int[10];
int len = 0;
do {
temp[len] = n % 9;
n /= 9;
len++;
} while (n > 0);
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Queue;
public final class infinitybyone implements TestSolution {
public static void main(String[] args) {
System.out.println(new infinitybyone().run());
}
private static final int LIMIT = Library.pow(10, 7);
public String run() {
boolean[] isPrime = Library.listPrimality(LIMIT);
int[] pathMax = new int[isPrime.length];
Arrays.fill(pathMax, Integer.MAX_VALUE);
Queue<IntPair> queue = new PriorityQueue<>();
queue.add(new IntPair(2, 2));
while (!queue.isEmpty()) {
IntPair item = queue.remove();
int n = item.b;
int pmax = item.a;
if (pmax >= pathMax[n]) {
continue;
}
pathMax[n] = pmax;
int[] digits = toDigits(n);
int[] tempDigits = digits.clone();
for (int i = 0; i < tempDigits.length; i++) {
for (int j = 0; j < 10; j++) {
tempDigits[i] = j;
int m = toNumber(tempDigits);
int nextPmax = Math.max(m, pmax);
if (m < isPrime.length && isPrime[m] && nextPmax < pathMax[m])
queue.add(new IntPair(nextPmax, m));
}
tempDigits[i] = digits[i];
}
}
long sum = 0;
for (int i = 0; i < isPrime.length; i++) {
if (isPrime[i] && pathMax[i] > i)
sum += i;
}
return Long.toString(sum);
}
private static int[] toDigits(int n) {
if (n < 0)
throw new IllegalArgumentException();
//************This is PROBABLY where you made the error************
int[] temp = new int[11];
int len = 0;
do {
temp[len] = n % 10;
n /= 10;
len++;
} while (n > 0);
int[] result = new int[len + 1];
for (int i = 0; i < result.length; i++)
result[i] = temp[len - i];
return result;
}
private static int toNumber(int[] digits) {
int result = 0;
for (int x : digits)
result = result * 10 + x;
return result;
}
private static class IntPair implements Comparable<IntPair> {
public final int a;
public final int b;
public IntPair(int a, int b) {
this.a = a;
this.b = b;
}
public int compareTo(IntPair other) {
return Integer.compare(a, other.a);
}
}
}
I can't really tell where you messed up but at least from the code you shared, tell me why would you use 10 instead of 11? It should extract base-10 in little endian.

Quickselect that runs in O(n) in Java?

So I'm implement a quickselect algorithm that chooses a good pivot each time. What it does is divide the array into groups of 5, sorts each groups and finds the median. It then takes the medians of each group, groups those values up and then finds the median of medians. Here's what I have:
private static int pickCleverPivot(int left, int right, int[] A){
int index = 0;
int n = right-left;
if (n <= 5) {
Arrays.sort(A);
index = n/2;
return index;
}
int numofMedians = (int) Math.ceil(n/5);
int[] medians = new int[numofMedians];
int[] groups = new int[5];
for(int i = 0; i < numofMedians; i++) {
if (i != numofMedians - 1){
for (int j = 0; j < 5; j++){
groups[j] = A[(i*5)+j];
}
medians[i] = findMedian(groups, 5);
} else {
int numOfRemainders = n % 5;
int[] remainder = new int[numOfRemainders];
for (int j = 0; j < numOfRemainders; j++){
remainder[j] = A[(i*5)+j];
}
medians[i] = findMedian(groups, 5);
}
}
return pickCleverPivot(left, left+(numofMedians), medians);
}
public static int findMedian(int[] A, int n){
Arrays.sort(A);
if (n % 2 == 0) {
return (A[n/2] + A[n/2 - 1]) / 2;
}
return A[n/2];
}
private static int partition(int left, int right, int[] array, int pIndex){
//move pivot to last index of the array
swap(array,pIndex,right);
int p=array[right];
int l=left;
int r=right-1;
while(l<=r){
while(l<=r && array[l]<=p){
l++;
}
while(l<=r && array[r]>=p){
r--;
}
if (l<r){
swap(array,l,r);
}
}
swap(array,l,right);
return l;
}
private static void swap(int[]array, int a, int b){
int tmp = array[a];
array[a] = array[b];
array[b] = tmp;
}
So it works like it's supposed to but now I'm wondering if it's possible to get it to run in linear O(n) time. I'm currently comparing this code to just choosing a random pivot. On smaller arrays this code runs faster but on larger arrays, choosing a random pivot is faster. So is it actually possible to make this run in O(n) time or is that just in theory and if it's not possible for it to run that fast then is this method running as fast as it could.

Java - Rotating array

So the goal is to rotate the elements in an array right a times.
As an example; if a==2, then array = {0,1,2,3,4} would become array = {3,4,0,1,2}
Here's what I have:
for (int x = 0; x <= array.length-1; x++){
array[x+a] = array[x];
}
However, this fails to account for when [x+a] is greater than the length of the array. I read that I should store the ones that are greater in a different Array but seeing as a is variable I'm not sure that's the best solution.
Thanks in advance.
Add a modulo array length to your code:
// create a newArray before of the same size as array
// copy
for(int x = 0; x <= array.length-1; x++){
newArray[(x+a) % array.length ] = array[x];
}
You should also create a new Array to copy to, so you do not overwrite values, that you'll need later on.
In case you don't want to reinvent the wheel (maybe it's an exercise but it can be good to know), you can use Collections.rotate.
Be aware that it requires an array of objects, not primitive data type (otherwise you'll swap arrays themselves in the list).
Integer[] arr = {0,1,2,3,4};
Collections.rotate(Arrays.asList(arr), 2);
System.out.println(Arrays.toString(arr)); //[3, 4, 0, 1, 2]
Arraycopy is an expensive operation, both time and memory wise.
Following would be an efficient way to rotate array without using extra space (unlike the accepted answer where a new array is created of the same size).
public void rotate(int[] nums, int k) { // k = 2
k %= nums.length;
// {0,1,2,3,4}
reverse(nums, 0, nums.length - 1); // Reverse the whole Array
// {4,3,2,1,0}
reverse(nums, 0, k - 1); // Reverse first part (4,3 -> 3,4)
// {3,4,2,1,0}
reverse(nums, k, nums.length - 1); //Reverse second part (2,1,0 -> 0,1,2)
// {3,4,0,1,2}
}
public void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
Another way is copying with System.arraycopy.
int[] temp = new int[array.length];
System.arraycopy(array, 0, temp, a, array.length - a);
System.arraycopy(array, array.length-a, temp, 0, a);
I think the fastest way would be using System.arrayCopy() which is native method:
int[] tmp = new int[a];
System.arraycopy(array, array.length - a, tmp, 0, a);
System.arraycopy(array, 0, array, a, array.length - a);
System.arraycopy(tmp, 0, array, 0, a);
It also reuses existing array. It may be beneficial in some cases.
And the last benefit is the temporary array size is less than original array. So you can reduce memory usage when a is small.
Time Complexity = O(n)
Space Complexity = O(1)
The algorithm starts with the first element of the array (newValue) and places it at its position after the rotation (newIndex). The element that was at the newIndex becomes oldValue. After that, oldValue and newValue are swapped.
This procedure repeats length times.
The algorithm basically bounces around the array placing each element at its new position.
unsigned int computeIndex(unsigned int len, unsigned int oldIndex, unsigned int times) {
unsigned int rot = times % len;
unsigned int forward = len - rot;
// return (oldIndex + rot) % len; // rotating to the right
return (oldIndex + forward) % len; // rotating to the left
}
void fastArrayRotation(unsigned short *arr, unsigned int len, unsigned int rotation) {
unsigned int times = rotation % len, oldIndex, newIndex, length = len;
unsigned int setIndex = 0;
unsigned short newValue, oldValue, tmp;
if (times == 0) {
return;
}
while (length > 0) {
oldIndex = setIndex;
newValue = arr[oldIndex];
while (1) {
newIndex = computeIndex(len, oldIndex, times);
oldValue = arr[newIndex];
arr[newIndex] = newValue;
length--;
if (newIndex == setIndex) { // if the set has ended (loop detected)
break;
}
tmp = newValue;
newValue = oldValue;
oldValue = tmp;
oldIndex = newIndex;
}
setIndex++;
}
}
int[] rotate(int[] array, int r) {
final int[] out = new int[array.length];
for (int i = 0; i < array.length; i++) {
out[i] = (i < r - 1) ? array[(i + r) % array.length] : array[(i + r) % array.length];
}
return out;
}
The following rotate method will behave exactly the same as the rotate method from the Collections class used in combination with the subList method from the List interface, i.e. rotate (n, fromIndex, toIndex, dist) where n is an array of ints will give the same result as Collections.rotate (Arrays.asList (n).subList (fromIndex, toIndex), dist) where n is an array of Integers.
First create a swap method:
public static void swap (int[] n, int i, int j){
int tmp = n[i];
n[i] = n[j];
n[j] = tmp;
}
Then create the rotate method:
public static void rotate (int[] n, int fromIndex, int toIndex,
int dist){
if(fromIndex > toIndex)
throw new IllegalArgumentException ("fromIndex (" +
fromIndex + ") > toIndex (" + toIndex + ")");
if (fromIndex < toIndex){
int region = toIndex - fromIndex;
int index;
for (int i = 0; i < dist % region + ((dist < 0) ? region : 0);
i++){
index = toIndex - 1;
while (index > fromIndex)
swap (n, index, --index);
}
}
}
Java solution wrapped in a method:
public static int[] rotate(final int[] array, final int rIndex) {
if (array == null || array.length <= 1) {
return new int[0];
}
final int[] result = new int[array.length];
final int arrayLength = array.length;
for (int i = 0; i < arrayLength; i++) {
int nIndex = (i + rIndex) % arrayLength;
result[nIndex] = array[i];
}
return result;
}
For Left Rotate its very simple
Take the difference between length of the array and number of position to shift.
For Example
int k = 2;
int n = 5;
int diff = n - k;
int[] array = {1, 2, 3, 4, 5};
int[] result = new int[array.length];
System.arraycopy(array, 0, result, diff, k);
System.arraycopy(array, k, result, 0, diff);
// print the output
Question : https://www.hackerrank.com/challenges/ctci-array-left-rotation
Solution :
This is how I tried arrayLeftRotation method with complexity o(n)
looping once from k index to (length-1 )
2nd time for 0 to kth index
public static int[] arrayLeftRotation(int[] a, int n, int k) {
int[] resultArray = new int[n];
int arrayIndex = 0;
//first n-k indexes will be populated in this loop
for(int i = k ; i
resultArray[arrayIndex] = a[i];
arrayIndex++;
}
// 2nd k indexes will be populated in this loop
for(int j=arrayIndex ; j<(arrayIndex+k); j++){
resultArray[j]=a[j-(n-k)];
}
return resultArray;
}
package com.array.orderstatistics;
import java.util.Scanner;
public class ArrayRotation {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int r = scan.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for (int i = 0; i < n; i++) {
a[i] = scan.nextInt();
}
scan.close();
if (r % n == 0) {
printOriginalArray(a);
} else {
r = r % n;
for (int i = 0; i < n; i++) {
b[i] = a[(i + r) < n ? (i + r) : ((i + r) - n)];
System.out.print(b[i] + " ");
}
}
}
private static void printOriginalArray(int[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
Following routine rotates an array in java:
public static int[] rotateArray(int[] array, int k){
int to_move = k % array.length;
if(to_move == 0)
return array;
for(int i=0; i< to_move; i++){
int temp = array[array.length-1];
int j=array.length-1;
while(j > 0){
array[j] = array[--j];
}
array[0] = temp;
}
return array;
}
You can do something like below
class Solution {
public void rotate(int[] nums, int k) {
if (k==0) return;
if (nums == null || nums.length == 0) return;
for(int i=0;i<k;i++){
int j=nums.length-1;
int temp = nums[j];
for(;j>0;j--){
nums[j] = nums[j-1];
}
nums[0] = temp;
}
}
}
In the above solution, k is the number of times you want your array to rotate from left to right.
Question : Rotate array given a specific distance .
Method 1 :
Turn the int array to ArrayList. Then use Collections.rotate(list,distance).
class test1 {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6 };
List<Integer> list = Arrays.stream(a).boxed().collect(Collectors.toList());
Collections.rotate(list, 3);
System.out.println(list);//[4, 5, 6, 1, 2, 3]
}// main
}
I use this, just loop it a times
public void rotate(int[] arr) {
int temp = arr[arr.length - 1];
for(int i = arr.length - 1; i > 0; i--) {
arr[i] = arr[i - 1];
}
arr[0] = temp;
}

Split array into pieces of X length

Currently I have an array of size N. I'm trying to copy every X amount of bytes from the array.
Example if the array is size 10 and I want arrays of size 3. I'd copy the first 3 elements then the next 3 and the last 1.
Currently I'm using the following algorithm:
int I = 0;
int sub = bytes.length;
int counter = 0;
for (I = 0; I < bytes.length; ++I) {
if (I % 3 == 0 && I != 0) {
NewArray[counter] = Arrays.copyOfRange(bytes, I - 3, I));
sub -= 3;
++counter;
}
}
NewArray[counter] = Arrays.copyOfRange(bytes, I - sub, I)); //Copy remainder.
Is there a more efficient or a more decent way of doing the what I want? This algorithm looks pretty bad =l
Any ideas how I can improve it or at least a hint?
What about this:
int x = 3; // chunk size
int len = bytes.length;
int counter = 0;
for (int i = 0; i < len - x + 1; i += x)
newArray[counter++] = Arrays.copyOfRange(bytes, i, i + x);
if (len % x != 0)
newArray[counter] = Arrays.copyOfRange(bytes, len - len % x, len);
Here's a convenient method that converts a byte[] to an array of byte[]'s. So, the result is a byte[][].
public byte[][] splitBytes(final byte[] data, final int chunkSize)
{
final int length = data.length;
final byte[][] dest = new byte[(length + chunkSize - 1)/chunkSize][];
int destIndex = 0;
int stopIndex = 0;
for (int startIndex = 0; startIndex + chunkSize <= length; startIndex += chunkSize)
{
stopIndex += chunkSize;
dest[destIndex++] = Arrays.copyOfRange(data, startIndex, stopIndex);
}
if (stopIndex < length)
dest[destIndex] = Arrays.copyOfRange(data, stopIndex, length);
return dest;
}
Some advantages compared to the previous best answer:
The for condition uses a <= which makes more sense than < ... + 1.
Putting the stop-index in a temporary field reduces the number of calculations in the last if block.
(Unit tested)
Few things to do here:
First, common conventions frown apon using capitals to start variable names, change the I and NewArray variables to 'i' and 'newArray' respectively.
Then, your code does not work because your first time through the loop, i-3 will lead to an IndexOutOfBounds exception.....
Finally, you do not show how you set the size of the newArray array.
int sublen = 3; // how many elements in each sub array.
int size = ((bytes.length - 1) / sublen) + 1; // how many newArray members we will need
byte[][] newArray = new byte[size][];
int to = byte.length;
int cursor = size - 1;
int from = cursor * sublen;
while (cursor >= 0) {
newArray[cursor] = Arrays.copyOfRange(bytes, from, to);
to = from;
from -= sublen;
cursor --;
}
Here's my implementation for this, it will split your array in sub-arrays of up to a maximum size you decide on, and put the sub-arrays into a list of arrays. The last array will be smaller if the size of the array is not a multiple of the maximum size chosen.
import java.util.Arrays;
...
public static <T> List<T[]> splitArray(T[] items, int maxSubArraySize) {
List<T[]> result = new ArrayList<T[]>();
if (items ==null || items.length == 0) {
return result;
}
int from = 0;
int to = 0;
int slicedItems = 0;
while (slicedItems < items.length) {
to = from + Math.min(maxSubArraySize, items.length - to);
T[] slice = Arrays.copyOfRange(items, from, to);
result.add(slice);
slicedItems += slice.length;
from = to;
}
return result;
}
Here is a function to split arrays, you can use below main method to test it.
private static List<Integer[]> splitArray(Integer[] originalArray, int chunkSize) {
List<Integer[]> listOfArrays = new ArrayList<Integer[]>();
int totalSize = originalArray.length;
if(totalSize < chunkSize ){
chunkSize = totalSize;
}
int from = 0;
int to = chunkSize;
while(from < totalSize){
Integer[] partArray = Arrays.copyOfRange(originalArray, from, to);
listOfArrays.add(partArray);
from+= chunkSize;
to = from + chunkSize;
if(to>totalSize){
to = totalSize;
}
}
return listOfArrays;
}
Testing method:
public static void main(String[] args) {
List<Integer> testingOriginalList = new ArrayList<Integer>();
for(int i=0;i<200;i++){
testingOriginalList.add(i);
}
int batchSize = 51;
Integer[] originalArray = testingOriginalList.toArray(new Integer[]{});
List<Integer[]> listOfArrays = splitArray(originalArray, batchSize);
for(Integer[] array : listOfArrays){
System.out.print(array.length + ", ");
System.out.println(Arrays.toString(array));
}
}
I know that this question is pretty old but hey, someone could search for another clean Java answer for this common question.
It you are working with List (Java 7), there is a pretty simple and clean method to get a portion of a list : List.subList( fromIndex, toIndex )
It's straightforward to use. If I take the question example, it would be like :
int chunkSize = 3;
int counter = 0;
// bytes must be a List like an ArrayList
List<Byte> byteList = Arrays.asList(bytes);
int length = byteList.size();
for (int fromIndex = 0; fromIndex < length; fromIndex += chunkSize) {
int toIndex = fromIndex + chunkSize;
if(toIndex > length){
toIndex = length;
}
NewArray[counter] = byteList.subList(fromIndex, toIndex);
counter++;
}
// Now NewArray[] contain sub array and the last one is of the remaining length
To get ride of the 'counter', some could change the way NewArray is build for a List approach as well, with something like :
// NewArray must be a List<List<Byte>>
NewArray.addAll(byteList.subList(fromIndex, toIndex));
Hope this will help someone in the future !
You can use split with a special regular expression:
System.out.println(Arrays.toString(
"Thisismystringiwanttosplitintogroupswith4chareach".split("(?<=\\G.{4})")
));
Credit to earlier post by Alan Moore. Please visit and vote up.
If actually you need quite big chunks, and don't want to modify their contents independently, consider reusing the same initial array by means of ByteBuffer.wrap() and then slice() repeatedly. This would prevent unnecessary copying and memory waste.
import java.util.Arrays;
public class Test {
private void run() {
try {
byte[] cfsObjIds = "abcdefghij".getBytes();
System.out.println(Arrays.toString(cfsObjIds));
final int chunkSize = 4;
System.out.println("Split by " + chunkSize + ":");
int objQty = cfsObjIds.length;
for (int i = 0; i < objQty; i += chunkSize) {
int chunkUpperLimit = Math.min(objQty, i + chunkSize);
byte[] cfsIdsChunk = Arrays.copyOfRange(cfsObjIds, i, chunkUpperLimit);
System.out.println(Arrays.toString(cfsIdsChunk));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
new Test().run();
}
}

Adding Data Values to a Search Algorithm?

How do I add say 1000, 10000, 1000000, or 10000000 individual data items to a search algorithm?
Code:
public class BinarySearch {
int binarySearch(int[] array, int value, int left, int right) {
if (left > right)
return -1;
int middle = (left + right) / 2;
if (array[middle] == value)
return middle;
else if (array[middle] > value)
return binarySearch(array, value, left, middle - 1);
else
return binarySearch(array, value, middle + 1, right);
}
}
So, if I understand correctly, you want to try your algorithm with different amounts of integers in your array.
public int[] makeArray(int size, int minNum, int maxNum) {
int [] arr = new int[size];
Random r = new Random();
for (int i = 0; i < size; i++) {
arr[i] = minNum + r.nextInt(maxNum);
}
Arrays.sort(arr);
return arr;
}
So if you want to have 10000 numbers ranging from 100 to 500, then you would call:
int[] arr = makeArray(10000, 100, 500);
Actually, I recommend making a helper method to start off your searches like so:
public int binarySearch(int[] array, int value) {
return binarySearch(array, value, 0, array.length - 1);
}
Then you can look in arr for a value (e.g., 5):
int i = binarySearch(arr, 5);
It seems that you are asking how to populate the array. Here is one way to do it:
final Random rnd = new Random();
final int n = 100000;
final int[] array = new int[n];
for (int i = 0; i < n; ++i) {
array[i] = rnd.nextInt();
}
Arrays.sort(array);

Categories