Randomly filling a 2d boolean array with equal amounts of both values - java

I'm trying to find a way to fill a 2d array of length n with boolean values randomly. The array must have an equal amount of each value if n is even, and if n is odd the extra value must be the same boolean each and every time (doesn't matter which one). Any tips on how to do this in Java? I'm currently shuffling arrays that I make with equal amounts of both values, but this isn't truly random because there will always be n/2 (or n/2+1 and n/2-1 for the odd ns) of each value.
Any advice?

Given your requirements, filling the array with the amount you need, then shuffling it, is a good solution.
Make sure to use a truly random shuffling algorithm, such as the Fisher-Yates shuffle, not the "swap a random pair a bunch of times" method. If you're using Collections.shuffle or similar, you don't need to worry about this.

Adapting the Fisher-Yates shuffle to a 2D array is probably the simplest approach.
boolean[][] array = new boolean[rows][cols];
boolean alternating = false;
Random random = new Random();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int k = random.nextInt(i * cols + j + 1);
int swapRow = k / cols;
int swapCol = k % cols;
boolean tmp = array[swapRow][swapCol];
array[swapRow][swapCol] = alternating;
array[i][j] = tmp;
alternating = !alternating;
}
}
This is pretty much a verbatim implementation of http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_.22inside-out.22_algorithm , except that we're filling the array as we go with falses and trues.

A different approach might be to randomise the position you are placing the next value rather than the value itself. You know ahead of time exactly how many of each value you are placing.
Something like:
List<Integer> indicesList = IntStream.range(0, n * n).collect(Collectors.toList());
Collections.shuffle(indicesList);
indicesList.stream().forEach(n -> array[n % size][n / size] = (n % 2 == 0));
By my understanding that should give you completely random placement of your values and an equal number of each.

Here's a real simple solution a coworker came up with. It looks to me like it would work and be truly random (please let me know if not, I have terrible intuition about that kind of thing), although it's definitely ugly. Would be pretty efficient compared to a shuffle I imagine.
public boolean[][] generateRandom2dBooleanArray(int length) {
int numFalses = (length*length)/2;
int numTrues = (length*length)/2;
if ((length*length)%2!=0) numTrues++;
boolean[][] array = new boolean[length][length];
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if (Math.random() > 0.5) {//Or is it >= 0.5?
if (numTrues >= 0) {
array[i][j] = true;
numTrues--;
} else {
//Since boolean arrays are false by default, you could probably just break here to get the right anser, but...
array[i][j] = false;
numFalses--;
}
} else {
if (numFalses >= 0) {
array[i][j] = false;
numFalses--;
} else {
array[i][j] = true;
numTrues--;
}
}
}
}
}
return array;
}

Related

comparing elements in an array and fetching new ones

I realize this has been asked before and I had a look at it but, for me, it only works to a point. After some struggle, I thought I'd ask.
I have an array of floats in an object's constructor.
That goes like this:
count = 3;
angles = new float[count];
The array length is really small though I'd like implement a modular and reusable approach.
I loop through the array assigning floats:
for (int i = 0; i < angles.length; i++) {
angles[i] = radians(random(360));
}
Then, with a new loop, I check if the singular elements have less than 30 degrees in between them, and if so, assign a new random value:
for (int i = 0; i < angles.length; i++) {
for (int k = i+1; k < angles.length; k++){
if(angles[i] != angles[k]){
if(abs(angles[i] - angles[k]) <= radians(30)){
angles[i] = radians(random(360));
}
}
}
}
This works nice and well but it doesn't guarantee that the new random number will keep the 30 degrees limit with the remaining elements. This, I assume, has to do with the length of the 'for' loop.
What would be the best way to overcome this and guarantee that newly fetched number will always conform to the 30 degree rule?
Instead of just checking once with an if statement, you could change it to a while statement, so that it attempts to find a new random number until the new one works.
while (abs(angles[i] - angles[k]) <= radians(30)){
angles[i] = radians(random(360));
}
However, if there are no numbers that follow your 30 degree rule, your program will get stuck in this loop, so you might want to check that there is a possible solution before entering the loop.
Edit: the above solution will ensure that the number follows the 30 degree rule with only one number in your array. Add a boolean to determine if the condition has been met, and loop until the boolean is true.
for (int i = 0; i < angles.length; i++) {
boolean meetsCondition = false;
while (!meetsCondition) {
for (int k = 0; k < angles.length; k++){
if(i != k){
if(abs(angles[i] - angles[k]) <= radians(30)){
angles[i] = radians(random(360));
meetsCondition = false;
break;
}
}
}
meetsCondition = true; //if the for loop completes, it has met the condition.
}
}
Why not use recursion earlier on:
for (int i = 0; i < angles.length; i++) {
angles[i] = findSuitable( i==0 ? 0 : angles[i-1] )
}
...
float findSuitable(float limit){
float sample = radians(random(360));
if(Math.abs(sample-limit) > 30)
return sample;
else
return findSuitable(limit);
}
In my opinion, you can try to change the the codes of random to this:
Random d = new Random();
int a = d.nextInt(360);

How to check if every element in an array is lower than another array in Java?

Right now I have the following idea:
int WORK[] = new int[]{5, 4, 3};
int release[] = new int[]{3, 2, 3};
boolean check = false;
for (int i = 0; i < WORK.length; i++)
{
if (WORK[i] >= release[i])
{
for (int j = 0; j < WORK.length; j++)
{
if (WORK[j] >= release[j])
{
for (int k = 0; k < WORK.length; k++)
{
if (WORK[k] >= release[k])
{
check = true;
System.out.print("All elements in work are bigger than release");
break;
}
}
break;
}
}
break;
}
}
if(!check)
{
System.out.print("Not every element in work is bigger than release");
}
Now I want to know if there is a more efficient way to do this? But my main problem is that I need to do this with n elements. With `nĀ“ elements it is not efficient neither useful, because I don't know how many elements will be there.
What I want to know is there a function in Java Arrays or something, which could help me?
Any help?
With Java 8, you can do this in a functional style with streams (this would not be a performance optimization; it's just less code to write).
IntPredicate lowerThanRelease = i -> IntStream.of(release).allMatch(j -> i <= j);
boolean allLower = IntStream.of(work).allMatch(lowerThanRelease);
One efficient way to do this is two have 4 variables
workmax, workmin, needmax, needmin.
Iterate through both arrays one at a time and find the max and min values within that array. Then all you need to do is compare the min value of one array with max value of the second array
This way you just need two loops (no nesting).
Then its a matter of simple comparison.
e.g.
if (workmin > needmax) then System.out.print("All elements in " + work + "are bigger than need");
I think you can come up with the code if you understand the approach mentioned above.
I hope I got your question correctly.
if (array1.length == array2.length) {
for (int i = 0; i < array1.length; i++) {
for (int j =0; j < array2.length; j++) {
// compare array1[i] with array2[j];
}
}
} else {
System.out.println("Arrays have different lengths.");
}
This gives you the opportunity to compare all numbers of one array with all numbers of the second. So your basic idea was not that bad.
Hope it helps.
This one seems very basic, but it should do it.

How would you find how many times one array is repeated in another one?

For example, if you were given {1,2} as the small array and {1,2,3,4,1,2,1,3} as the big one, then it would return 2.
This is probably horribly incorrect:
public static int timesOccur(int[] small, int big[]) {
int sum= 0;
for (int i=0; i<small.length; i++){
int currentSum = 0;
for (int j=0; j<big.length; j++){
if (small[i] == big[j]){
currentSum ++;
}
sum= currentSum ;
}
}
return sum;
}
As #AndyTurner mentioned, your task can be reduced to the set of well-known string matching algorithms.
As I can understand you want solution faster than O(n * m).
There are two main approaches. First involves preprocessing text (long array), second involves preprocessing search pattern (small array).
Preprocessing text. By this I mean creating suffix array or LCP from your longer array. Having this data structure constructed you can perform a binary search to find your your substring. The most efficient time you can achieve is O(n) to build LCP and O(m + log n) to perform the search. So overall time is O(n + m).
Preprocessing pattern. This means construction DFA from the pattern. Having DFA constructed it takes one traversal of the string (long array) to find all occurrences of substring (linear time). The hardest part here is to construct the DFA. Knuth-Morris-Pratt does this in O(m) time, so overall algorithm running time will be O(m + n). Actually KMP algorithm is most probably the best available solution for this task in terms of efficiency and implementation complexity. Check #JuanLopes's answer for concrete implementation.
Also you can consider optimized bruteforce, for example Boyer-Moore, it is good for practical cases, but it has O(n * m) running time in worst case.
UPD:
In case you don't need fast approaches, I corrected your code from description:
public static int timesOccur(int[] small, int big[]) {
int sum = 0;
for (int i = 0; i < big.length - small.length + 1; i++) {
int j = 0;
while (j < small.length && small[j] == big[i + j]) {
j++;
}
if (j == small.length) {
sum++;
}
}
return sum;
}
Pay attention on the inner while loop. It stops as soon as elements don't match. It's important optimization, as it makes running time almost linear for best cases.
upd2: inner loop explanation.
The purpose of inner loop is to find out if smaller array matches bigger array starting from position i. To perform that check index j is iterated from 0 to length of smaller array, comparing the element j of the smaller array with the corresponding element i + j of the bigger array. Loop proceeds when both conditions are true at the same time: j < small.length and corresponding elements of two arrays match.
So loop stops in two situations:
j < small.length is false. This means that j==small.length. Also it means that for all j=0..small.length-1 elements of the two arrays matched (otherwise loop would break earlier, see (2) below).
small[j] == big[i + j] is false. This means that match was not found. In this case loop will break before j reaches small.length
After the loop it's sufficient to check whether j==small.length to know which condition made loop to stop and hence know whether match was found or not for current position i.
This is a simple subarray matching problem. In Java you can use Collections.indexOfSublist, but you would have to box all the integers in your array. An option is to implement your own array matching algorithm. There are several options, most string searching algorithms can be adapted to this task.
Here is an optimized version based on the KMP algorithm. In the worst case it will be O(n + m), which is better than the trivial algorithm. But it has the downside of requiring extra space to compute the failure function (F).
public class Main {
public static class KMP {
private final int F[];
private final int[] needle;
public KMP(int[] needle) {
this.needle = needle;
this.F = new int[needle.length + 1];
F[0] = 0;
F[1] = 0;
int i = 1, j = 0;
while (i < needle.length) {
if (needle[i] == needle[j])
F[++i] = ++j;
else if (j == 0)
F[++i] = 0;
else
j = F[j];
}
}
public int countAt(int[] haystack) {
int count = 0;
int i = 0, j = 0;
int n = haystack.length, m = needle.length;
while (i - j <= n - m) {
while (j < m) {
if (needle[j] == haystack[i]) {
i++;
j++;
} else break;
}
if (j == m) count++;
else if (j == 0) i++;
j = F[j];
}
return count;
}
}
public static void main(String[] args) {
System.out.println(new KMP(new int[]{1, 2}).countAt(new int[]{1, 2, 3, 4, 1, 2, 1, 3}));
System.out.println(new KMP(new int[]{1, 1}).countAt(new int[]{1, 1, 1}));
}
}
Rather than posting a solution I'll provide some hints to get your moving.
It's worth breaking the problem down into smaller pieces, in general your algorithm should look like:
for each position in the big array
check if the small array matches that position
if it does, increment your counter
The smaller piece is then checking if the small array matches a given position
first check if there's enough room to fit the smaller array
if not then the arrays don't match
otherwise for each position in the smaller array
check if the values in the arrays match
if not then the arrays don't match
if you get to the end of the smaller array and they have all matched
then the arrays match
Though not thoroughly tested I believe this is a solution to your problem. I would highly recommend using Sprinters pseudocode to try and figure this out yourself before using this.
public static void main(String[] args)
{
int[] smallArray = {1,1};
int[] bigArray = {1,1,1};
int sum = 0;
for(int i = 0; i < bigArray.length; i++)
{
boolean flag = true;
if(bigArray[i] == smallArray[0])
{
for(int x = 0; x < smallArray.length; x++)
{
if(i + x >= bigArray.length)
flag = false;
else if(bigArray[i + x] != smallArray[x])
flag = false;
}
if(flag)
sum += 1;
}
}
System.out.println(sum);
}
}

Java 2D array encirclement

I am tasked to make a program which returns true if in a 2D array 1-s encircle 0-s.
I tried something like this, but i cant find the right solution.
public boolean checkGameState(){
for(int i=0;i<fields.length;i++){
for(int j=0;j<fields.length;j++){
if(fields[i][j]!=0){
if(row(i,j){
return true;
}
}
}
}
return false;
}
private boolean row(int a, int b){
int checkI=a;
int checkJ=b;
while(fields[checkI][checkJ]==1){
checkJ++;
}
while(fields[checkI][checkJ]==1){
checkI++;
}
while(fields[checkI][checkJ]==1){
checkJ--;
}
while(fields[checkI][checkJ]==1){
checkI--;
}
return a==checkI && b==checkJ;
}
The 2D array looks something like this:
111100
100100
100101
111100
001100
For this array the method should return true.
The easiest way might be to use a flood fill algorithm to eliminate all the zeros that are not encircled by ones, and then checking whether there are any left.
First, put all the zeros directly on the "fringe" of the 2D array into a queue. Then, use the flood fill algorithm to turn all of those into a different number (e.g., 2), and add the nodes next to them to the fringe set (either diagonally or only direct neighbours). Repeat until there are no more nodes in the fringe. Finally, check whether there are any more zeros in the array. If so, those were not connected to the fringe region and thus had to be "encircled" by ones.
// test data set up
int[][] data = {{1,1,1,1,0,0},
{1,0,0,1,0,0},
{1,0,0,1,0,1},
{1,1,1,1,0,0},
{0,0,1,1,0,0}};
int N = data.length, M = data[0].length;
// create queue of zeros on the "fringe"
Queue<int[]> fringe = new LinkedList<>();
for (int i = 0; i < N; i++) {
if (data[i][0 ] == 0) fringe.add(new int[]{i,0 });
if (data[i][M-1] == 0) fringe.add(new int[]{i,M-1});
}
for (int j = 0; j < M; j++) {
if (data[0 ][j] == 0) fringe.add(new int[]{0 ,j});
if (data[N-1][j] == 0) fringe.add(new int[]{N-1,j});
}
// do flood fill until no more zeros reachable
while (! fringe.isEmpty()) {
int[] next = fringe.poll();
int i = next[0], j = next[1];
data[i][j] = 2;
for (int di = -1; di <= 1; di++) {
for (int dj = -1; dj <= 1; dj++) {
try {
if (data[i+di][j+dj] == 0) fringe.add(new int[]{i+di, j+dj});
} catch (ArrayIndexOutOfBoundsException e) {}
}
}
}
// check for remaining zeros
boolean encircled = false;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
System.out.print(data[i][j]);
encircled |= data[i][j] == 0;
}
System.out.println();
}
System.out.println(encircled);
Example output:
111122
100122
100121
111122
221122
true
The complexity should be on the order of O(NxM), since each of the NxM nodes can only appear once in the queue (plus a bit of overhead for constructing the queue and finding remaining zeros).
Please note that I have assumed that you need rectangle shape surrounding
You need to find sequences for 3 or more 1 in one row.
xx1111xx // x means any number
For each sequence check if there is sequence of the same length 2 or more rows lower.
xx1111xx
xxxxxxxx
xx1111xx
For each "pair" of sequences check if they are connected with 1 on the edges.
xx1111xx
xx1xx1xx
xx1111xx

Check to see if any duplicate index values exist within an array?

So basically, I have one array, with ten values...
int[] input = new int[10];
The user controls the input to each value.
What would be a good technique to check to see if any of the values inside of the array are equal to any of the other values?
Edit:
public static void main(String[] args) {
P2 numbers = new P2();
for (int i = 0; i < numbers.input.length; i++) {
numbers.input[i] = numbers.scan.nextInt();
}
numbers.Check();
if (numbers.Check()) { System.out.println("Duplicate"); }
if (numbers.Check() == false) { System.out.println("NOT Duplicate"); }
}
public boolean Check() {
int length = input.length;
for(int i : input) {
for(int j = i + 1; j < length; j++) {
if(input[i] == input[j]) return true;
}
}
return false;
}
The codes works ask long as duplicate numbers are index-neighbors.
If you really only have ten values in the array, you're better off with a double-nested loop that breaks when it finds a duplicate.
int length = input.length;
for(int i = 0; i < length; i++) {
for(int j = i + 1; j < length; j++) {
if(intput[i] == input[j]) return true;
}
}ā€‹
If you're expecting to scale up to a large number, you're better off populating a hashset and breaking when you find a value that's already in the Hashset.
HashSet<Integer> set = new HashSet<Integer>();
for(int i : input) {
if(set.contains(i)) return true;
set.add(i);
}ā€‹
You could
compare all values in two loops (inefficient)
sort the array and then only compare adjacent values. This is more efficient, especially for longer arrays.
The first one is very easy to implement and if your array only has a length of 10, this should suffice.
If the stored int values are small non-negative values, then a BitSet might be appropriate:
BitSet set = new BitSet();
for(int i : input) {
if(set.get(i)) return true;
set.set(i);
}ā€‹
If you instead have a wide range of values, and lots of them, but a low likelihood of there being a duplicate (i.e. you expect there to be no duplicates, and simply need to confirm that), you can hash the ints, and use a BitSet(8192) of the low 13 bits of the hash (for example). That only uses roughly 1k. This can be used to easily confirm that there are no duplicates, but if it does find a hash collision, then you need to re-check with a less efficient method.
You can also sort the array and scan quickly for duplicates. Compared to building a hashset, it won't use as much memory, but will be slower.

Categories