java - 2D array find random null value - java

I have a 2D array in which are some indexes null and some of indexes have value.
I want to select a random index that contains null.
example
5,0,0,5,0
4,0,0,4,7
9,0,4,8,9
0,8,4,0,1
i want to choose random index from these which are zero
thx for reply

Or you can try this : put index of '0' as key/value on a map, then :
Random random = new Random();
Map x= new HashMap();
x.put(0,1);
....
List keys = new ArrayList<Integer>(x.keySet());
Integer randomX = keys.get( random.nextInt(keys.size()) );
Integer value = x.get(randomX );

//Init array
int array[][] = { { 5, 0, 0, 5, 0 }, { 4, 0, 0, 4, 7 },
{ 9, 0, 4, 8, 9 }, { 0, 8, 4, 0, 1 } };
//Init vector for indices of elements with 0 value
ArrayList<int[]> indices = new ArrayList<int[]>();
//Find indices of element with 0 value
for (int i = 0; i < array.length; i++)
{
for (int j = 0; j < array[i].length; j++)
{
if (array[i][j] == 0)
{
indices.add(new int[] { i, j });
}
}
}
//Just print the possible candidates
for (int[] index : indices)
{
System.out.println("Index = (" + index[0] + ", " + index[1] + ")");
}
System.out.println();
//Select a random index and print the result
Random rand = new Random();
int ri = rand.nextInt(indices.size());
int[] index = indices.get(ri);
System.out.println("Selected index = (" + index[0] + ", " + index[1] + ")");
The solution is based that it is easy to select a random value in a 1D array. Therefore as the first step all the indices belongs to elements with value 0 are collected in a ArrayList object, then the select of a random element in this ArrayList object results the searched indices.

You could use simple trick - just map your zero values to array.
Or better solution is only count the number of zero values, so, you should iterate through your 2D array and compare values - if you want find zero, then it should be:
int count = 0;
for(int i=0;i< array.length;i++)
for(int j=0;j< array[i].length;j++)
if(array[i][j] == 0)
count++;
After that you can get random number from your interval 1-count and then iterate your 2D array and choose the zero number with random position.
int randomPosition = (int )(Math.random() * (count-1));
int now=0;
if(randomPosition > -1)
for(int i=0;i< array.length;i++)
for(int j=0;j< array[i].length;j++)
if(array[i][j]==0){
now++;
if(now == randomPosition){
rowPosition = i;
columnPosition = j;
}
}
This is not really the correct way how to do it and if you can, you should not use null values - or zeros as null values in your design, better think about another solution to save values in 2D arrays. Do you really need null values or zero values there?And why do you need return random null position?

From your question, I understand you want to select a random element (that contains 0) in a 2-dimensional array in Java. First of all, you should understand that since most numbers are value-based, 0 != null. This will help to make your question clearer.
Now, you will first have to loop through your array to determine which elements are 0, recording the positions where each 0 element is placed. Then, you generate a random number to determine which 0 element should be picked:
//determines amt of 0s in array
ArrayList<ArrayList<int>> keys = new ArrayList<>();
for (int i = 0; i < array.length; i++) {
ArrayList<int> inner = new ArrayList<int>();
for (int j = 0; j < array[i].length; j++) {
if (i == 0) { inner.add(j); }
}
keys.add(inner);
}
Random r = new Random();
//TODO: generate random number, determine which element to pick
Hope this helps.

This solution is maybe a bit long, but effective. I tried to solve this with java streams:
First what you need is to convert 2D array into a simple IntStream. The simplest way could be something like:
Arrays.stream(arr).flatMapToInt(intArr -> Arrays.stream(intArr));
Our stream now looks like this:
{5,0,0,0,5,0,4,0,0,4,7,9...}
Next you need to get stream with values like key-value (index-value in this case). This is quite hard with streams and there is maybe an easier solution, but I created a KeyValue class with auto-incrementation of index:
class KeyValue {
int index;
int value;
static int nextIndex;
public KeyValue(int v) {
this.index = nextIndex;
nextIndex++;
this.value = v;
}
public static void restart() {
nextIndex = 0;
}
}
Now it is easy to convert our stream to index-value items. Call:
.mapToObj(KeyValue::new)
Now our stream looks like this:
{KeyValue[i=0 v=5], KeyValue[i=1 v=0], KeyValue[i=2 v=0], KeyValue[i=3 v=0]...}
Now filter zeros and collect stream to an array:
.filter(kv -> kv.value == 0).toArray(KeyValue[]::new);
Whole code to create an array is:
KeyValue[] zeros = Arrays
.stream(arr)
.flatMapToInt(intArr -> Arrays.stream(intArr))
.mapToObj(KeyValue::new)
.filter(k -> k.value == 0)
.toArray(KeyValue[]::new);
Now it is pretty easy to get a random value from the array:
int ourResult = zeros[random.nextInt(zeros.length)].index;
Whole code will look like this:
int[][] arr = new int[][]
{
{5, 0, 0, 5, 0},
{4, 0, 0, 4, 7},
{9, 0, 4, 8, 9},
{0, 8, 4, 0, 1}
};
Random random = new Random();
KeyValue.restart();
KeyValue[] zeros = Arrays
.stream(arr)
.flatMapToInt(intArr -> Arrays.stream(intArr))
.mapToObj(KeyValue::new)
.filter(k -> k.value == 0)
.toArray(KeyValue[]::new);
int ourResult = zeros[random.nextInt(zeros.length)].index;
Happy coding :)

I was looking for this answer, and come up with this in processing:
// object to hold some info
class Point {
// public fields fine for Point object
public int i, j, count;
// constructor
public Point (int i, int j) {
this.i = i;
this.j = j;
this.count = 0;
}
public String toString() {
return i + " , " + j;
}
}
int[][] grid;
// processing needs to init grid in setup
void setup() {
// init grid
grid = new int[][] {
{5,1,2},
{3,4,4},
{4,0,1}
};
println(getRandomZero(new Point(0,0)));
}
// recursion try for 300 random samples
Point getRandomZero(Point e) {
// base case
Point p = e;
if (grid[p.i][p.j] != 0 && p.i < grid.length && p.j < grid[p.i].length) {
p.i = randomInt(0,grid.length);
p.j = randomInt(0,grid[p.i].length);
p.count++;
// if can't find it in 300 tries return null (probably not any empties)
if (p.count > 300) return null;
p = getRandomZero(p);
}
return p;
}
// use Random obj = new Random() for Java
int randomInt(int low, int high) {
float random = random(1);
return (int) ((high-low)*random)+low;
}
I'll edit for Java specifically tomorrow.

Related

Finding missing number(s) from an array

Written this code, would like to get better approach using any algorithm to find missing numbers from an sorted or unsorted array. If its an unsorted array, i would sort and execute the following.
private static void identifyMissingValues(Integer[] ar) {
for(int i = 0; i < (ar.length - 1); i++) {
int next = ar[i + 1];
int current = ar[i];
if((next - current) > 1) {
System.out.println("Missing Value : " + (current + 1));
}
}
}
Any code faster or better than this, please suggest.
Any code faster or better than this, please suggest.
No there is no such thing - you cannot improve on an O(n) algorithm if every element must be visited.
Use BitSet instead of sorting.
int[] ar = {7, 2, 6, 8, 10, 4, 3, 2};
int min = IntStream.of(ar).min().getAsInt();
BitSet b = new BitSet();
for (int i : ar)
b.set(i - min);
int i = 0;
while ((i = b.nextClearBit(i + 1)) < b.length())
System.out.println(i + min);
result
5
9
Sorting the array would take O(n*log(n)).
You can do better if you add all the elements of the array to a HashSet (O(n)) running time, and then check for each number between 0 and ar.length - 1 (or whatever the relevant range is) whether the HashSet contains that number. This would take O(n) time.
Your approach is good, but I added something more for more than one numbers are missing..
eg : ar={1,2,4,6,10} // Sorted Array
private static void identifyMissingValues(Integer[] ar) {
for (int i = 0; i < (ar.length - 1); i++) {
int next = ar[i + 1];
int current = ar[i];
if ((next - current) > 1) {
for (int ind = 1; ind < next - current; ind++)
System.out.println("Missing Value : " + (current + ind));
}
}
}
Output is,
Missing Value : 3
Missing Value : 5
Missing Value : 7
Missing Value : 8
Missing Value : 9
Can I know the Input and Expected output number series ?
According to your code i feel the series should be a difference of 1,If i'm not wrong.
So you have an array of n elements which starts with an integer i and contains all integers from i to i+n is that right? Eg:
arr = [1,2,3,4,5]
So, the sum of all numbers in the array should be the sum of numbers from i to i+n.
Eg: sum(arr) = 1+2+3+4+5 = 15
The formula for the sum of numbers 1 to n is n(n+1)/2
So you can have a for loop as:
int counter = 0;
for(Integer i : integers)
counter += i
To get the sum of numbers in your array.
If your array starts at one, you check whether the counter variable equals n(n+1)/2, where n is the length of your array.
If your array doesn't start at one, for example arr = [78, 79, 80, 81] then you need to tweak this approach a little, but I'm sure you can figure it.
You can do:
Set<Integer> mySet = new TreeSet<Integer>(Arrays.asList(ar));
int min = mySet.first();
for (int i = 0; i < mySet.size(); i++) {
int number = min + i;
if (!mySet.contains(number)) {
System.out.println ("Missing: " + number);
i--;
}
}
Integer [] list = new Integer[]{1, 12, 85, 6, 10};
Integer previous = null;
Arrays.sort(list);
System.out.println(list);
for(int index = 0; index < list.length; index++){
if(previous == null){
previous = (Integer) list[index];
continue;
}
Integer next = previous + 1;
if(((Integer) list[index] - previous) > 1){
System.out.println("Missing value " + next);
index--;
}
previous = next;
}

Java how to find the middle of a 2d array

I'm writing a function that tries to find the middle of a 2d array, and here's what I have so far:
int findMiddle(int[][] grid,int [] m) {
int[] list = new int[grid.length*grid[0].length];
int listPos = 0;
for(int i = 0 ; i < grid.length; i++) {
for(int j = 0; j < grid.length; j++) {
list[listPos++] = grid[i][j];
}
}
int middle = m.length/2;
if (m.length%2 == 1) {
return m[middle];
} else {
return (m[middle-1] + m[middle]) / 2.0;
}
}
Suppose I have an array of
{{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 0, 1}}
It should return 6, as it is integer division.
Also, the definition of middle in this code is the middle integer of the whole original array (needless to say if it is sorted or not).
How would I do this? ( my code also doesn't compile)
This compiles, and will give you the middle number in your sequence, or the average of the middle two if it splits the middle:
static double findMiddle(int[][] grid) {
int[] list = new int[grid.length*grid[0].length];
int listPos = 0;
for(int i = 0 ; i < grid.length; i++) {
for(int j = 0; j < grid[i].length; j++) {
list[listPos++] = grid[i][j];
}
}
int middle = list.length/2;
if ((list.length%2) == 1) {
return list[middle];
}
return (list[middle-1] + list[middle]) / 2.0;
}
However, I suspect you'll want to sort you numbers after you combine them into a single array, before you find the middle numbers. (as piyush121 commented)
Assuming your definition of 'median' is correct (the middle number of an odd length set or the average of the two middle numbers of an even length set), and if grid[][] is sorted, and if grid[][] is a square array (i.e. grid.length = grid[i].length for all i in 0..length-1, then you don't need to copy data to another array. The following should suffice:
static int findMiddle(int[][] grid) {
int l = grid.length;
if (l%2 == 1) {
return grid[l/2][l/2];
} else {
return (grid[l/2-1][l-1]+grid[l/2][0])/2;
};
Looking at your existing code it seems you are defining 'median' as the middle value in the matrix if all values were put into a single row-wise list. In other words you don't need to cope with odd numbers of rows (when two numbers from the same column are in the middle) or odd numbers of rows and columns (when there are four numbers in the middle).
If that definition is correct then you can cope with all the complexity of uneven rows by streaming all values and then selecting the middle ones.
For your interest, here's a Java 8 solution that does that:
int[] flat = Arrays.stream(grid).flatMapToInt(Arrays::stream).toArray();
double middle = Arrays.stream(flat).skip(flat.length / 2).limit(1 + flat.length % 2)
.average().getAsDouble();

Find widest subarray with given sum (array slicing)

I stumbled recently on a modified maximum sum subarray problem, here we know the sum (let's say it's S=2) but we need to find a longest slice of array which produces this exact sum (longest means must have biggest number of elements)
So for input array
A = [1, 0, -1, 1, 1, -1, -1]
We find 2 slices:
A(0:4) because sum(1,0,-1,1,1) is 2
and A(3:4) because sum(1,1) is also 2
But the A(0:4) subarray is the longest thus it's length 5 is the answer here..
Most of the solution's I found where not O(n) because they used 2 loops instead of a one or some packages for collections. Is this variant of problem even possible to solve with O(n) complexity?
I'm mostly interested in a solution written in Java, but don't know which algorithm to model.
assert solution(new int[] { 1, 0, -1, 1, 1, -1, -1 }, 2) == 5;
Best Regards
It can be done in O(n) as well:
First, create an auxilary array that sums each prefix of the array:
sums[i] = arr[0] + arr[1] + ... + arr[i]
The above can be computed in O(n) time.
Next, create a hash map Map<Integer,List<Integer>>, where the key is representing a prefix sum, and the value is a list of indices with this prefix sum. Pseudo code:
Map<Integer,List<Integer>> map = new HashMap<>();
for (int i = 0; i < sums.length; i++) {
List<Integer> l = map.get(sums[i]);
if (l == null) {
l = new ArrayList<>();
map.put(sums[i],l);
}
l.add(i);
}
Now, iterate the sums array, and for each element x, check if the map contains a key k such that x-k == S.
This is done by checking if it has a key k = S-x, which is O(1) in a hash map.
If there is such a key, then get the last index in the values list, which is also done in O(1), and take it as a candidate match.
Pseudo code:
int currentMaxLength = Integer.MIN_VALUE;
for (int i = 0; i < sums.length; i++) {
int k = S-sums[i];
List<Integer> l = map.get(k);
if (l == null) continue;
int width = Math.abs(l.getLast() - i);
if (width > currentMaxLength) currentMaxLength = width;
}
return currentMaxLength;
The idea is, if you have multiple matches for some x1,x2 such that x2-x1 = S, and where x1,x2 are prefix sums, the candidates for longest subarray are the first place where x1 appears, and the last place where x2 appears.
For x1, this is the element which i refers to in the main loop, and it is always regarded as a candidate.
For x2, you will always check the last occurance of x2, and thus it's correct.
Quicknote: The actual code also needs to regard sums[-1] = 0.
Java code:
public static int solution(int[] arr, int S) {
int[] sums = new int[arr.length+1];
int sum = 0;
//generate the sums array:
sums[0] = 0;
for (int i = 0; i < arr.length; i++) sums[i+1] = sum = sum+arr[i];
//generate map:
Map<Integer,List<Integer>> map = new HashMap<>();
for (int i = 0; i < sums.length; i++) {
List<Integer> l = map.get(sums[i]);
if (l == null) {
l = new ArrayList<>();
map.put(sums[i],l);
}
l.add(i);
}
//find longest:
int currentMaxLength = Integer.MIN_VALUE;
for (int i = 0; i < sums.length; i++) {
int k = S - sums[i];
List<Integer> l = map.get(k);
if (l == null) continue;
int width = Math.abs(l.get(l.size()-1) - i);
if (width > currentMaxLength) currentMaxLength = width;
}
return currentMaxLength;
}
public static void main(String[] args) {
System.out.println(solution(new int[] { 1, 0, -1, 1, 1, -1, -1 }, 2));
}
Think of something like this:
If you have a array T[A:D] and the maximum sub array of T[A:D] is T[B:C], then you get a next element T[E], you therefore need the maximum sub array of [A:E], this sub array MUST BE either the old T[B:C], or the T[B:E].

Substitution in an Array List

I have to list out 10 unique numbers between 1 and 20, but before storing the numbers, the program should check whether the number is in the list or not. If the number is already in the list, it should generate a new number. Also, the amount of numbers replaced must be counted.
This is what I have so far:
public static void main(String[] args)
{
int[] arrayA = {16, 14, 20, 3, 6, 3, 9, 1, 11, 2};
System.out.print("List: ");
for(int w = 0; w < arrayA.length; w++)
{
System.out.print(arrayA[w] + " ");
}
}
As you can see, there are two "3"s on the list, I have to output the same list but change one of the "3"s. Plus it has to be counted.
This is not hard to do, but what do you mean by change one of the threes?
You can add a boolean flag outside of your for loop that can tell if you've encountered a 3 or not and what the index of that 3 is.
Try something like this:
boolean changedThree = false;
int threeIndex = -1;
for(int i = 0; i < arrayA.length; i++){
if(arrayA[i] == 3 && !changedThree){
arrayA[i] = 4;
threeIndex = i;
changedThree = true;
}
System.out.println(arrayA[i] + " ");
}
I don't know for sure if that captures the information you need, but hopefully can give you a push in the right direction. Let me know if you have questions.
EDIT
To avoid any duplicate values, I recommend you create an array list, and add the unique values to it. Then, you can use the ArrayList.contains() method to see if a value exists already. So, I would recommend changing your code to this:
ArrayList<int> usedCharacters = new ArrayList<int>();
int changedCounter = 0;
Random rand = new Random();
for(int i = 0; i < arrayA.length; i++){
if(!usedCharacters.contains(arrayA[i])){ // If we haven't used this number yet
usedCharacters.add(arrayA[i]);
} else{
// Generate a new number - make sure we aren't creating a duplicate
int temp = rand.nextInt(20) + 1;
while(usedCharacters.contains(temp)){
temp = rand.nextInt(20) + 1;
}
// Assign new variable, increment counter
arrayA[i] = temp;
changedCounter++;
}
}
If you're not familiar with the random.nextInt() method, read this.
so if I understand you correctly you have to save the arrayA, right?
If that is the case, you can just make a new array, targetArray where you can save to numbers to, and then check using a for-loop if you already added it, and if so you can generate a new, random number.
The result would look something like this:
public static void main(String[] args) {
int[] arrayA = {16, 14, 20, 3, 6, 3, 9, 1, 11, 2};
int[] targetArray = new int[10];
int numbersReplaced = 0;
System.out.print("List: ");
for (int i = 0; i < arrayA.length; i++) {
for (int j = 0; j < targetArray.length; j++) {
if (arrayA[i] == targetArray[j]) {
targetArray[j] = (int)(Math.random() * 100);
numbersReplaced++;
} else {
targetArray[j] = arrayA[i];
}
}
}
System.out.println("Numbers replaced: " + numbersReplaced);
}
Hope that helped
You could use recursion to achieve your result.
This will keep looping until all values are unique
private void removeDoubles(int[] arr) {
for(int i = 0; i < arr.length; i++)
{
// iterate over the same list
for(int j = 0; j < arr.length; j++) {
// Now if both indexes are different, but the values are the same, you generate a new random and repeat the process
if(j != i && arr[i] == arr[j]) {
// Generate new random
arr[j] = random.nextInt(20);
// Repeat
removeDoubles(arr);
}
}
}
}
Note: This is the sort of question I prefer to give guidance answers rather than just paste in code.
You could walk the array backward looking at the preceding sublist. If it contain the current number you replace with a new one.
Get the sublist with something like Arrays.asList(array).subList(0, i) and then use .contains().
You logic for finding what number to add depends on lots of stuff, but at it simplest, you might need to walk the array once first to find the "available" numbers--and store them in a new list. Pull a new number from that list each time you need to replace.
EDIT: As suggested in the comments you can make use of Java Set here as well. See the Set docs.

Iterating over a sorted array and storing the count of distinct integers

Can somebody PLEASE answer my specific question, I cannot use material not covered in class yet and must do it this way.
I'm trying to iterate over a sorted array and if the previous number == the current number it stores the count in possiton n of a new array; when the previous number != the current number, it then moves to n+1 on the new array and starts counting again.
I'm debugging it now but having trouble working out what it isn't work. Any help is much appreciated.
// Get the count of instances.
int[] countOfNumbers = new int[50]; // Array to store count
int sizeOfArray = 0; // Last position of array filled
int instanceCounter = 1; // Counts number of instances
int previousNumber = 0; // Number stored at [k-1]
for (int k=1; k < finalArrayOfNumbers.length; k++) {
previousNumber = finalArrayOfNumbers[k-0];
if (previousNumber == finalArrayOfNumbers[k]) {
instanceCounter++;
countOfNumbers[sizeOfArray] = instanceCounter;
}
instanceCounter = 1;
sizeOfArray++;
countOfNumbers[sizeOfArray] = instanceCounter;
Don't worry about mapping or anything, I just need to know how If I have an array of:
[20, 20, 40, 40, 50]
I can get back
[2, 2, 1]
There's lots of neat tools in the Java API so you can avoid doing a lot of this yourself:
List<Integer> list = Arrays.asList(20, 20, 40, 40, 50);
Map<Integer, Integer> freq = new LinkedHashMap<>();
for (int i: list) {
freq.put(i, Collections.frequency(list, i));
}
System.out.println(freq.values());
That'll print [2, 2, 1] like you wanted.
Alternatively if you'd like a list of only the distinct values in the list, you can use an implementation of Set.
But since you're restricted because this is a class assignment, you could do something like this instead:
int[] a = { 20, 20, 40, 40, 50 };
int[] freq = new int[a.length];
// count frequencies
for (int i = 1, j = 0, count = 1; i <= a.length; i++, count++) {
if (i == a.length || a[i] != a[i - 1]) {
freq[j++] = count;
count = 0;
}
}
// print
for (int i = 0; i < freq.length && freq[i] != 0; i++) {
System.out.println(freq[i]);
}
And the output is still the same.
I put comments in the two places you were off, here's your fixed code.
for (int k = 1; k < finalArrayOfNumbers.length; k++) {
previousNumber = finalArrayOfNumbers[k - 1]; // changed 0 to 1
if (previousNumber == finalArrayOfNumbers[k]) {
instanceCounter++;
countOfNumbers[sizeOfArray] = instanceCounter;
} else { // put this last bit in an else block
instanceCounter = 1;
sizeOfArray++;
countOfNumbers[sizeOfArray] = instanceCounter;
}
}
I'm debugging it now but having trouble working out what it isn't work. Any help is much appreciated.
Here's a clue for you:
previousNumber = finalArrayOfNumbers[k-0];
if (previousNumber == finalArrayOfNumbers[k]) {
Clue: 'k - 0' has the same value as 'k' in the above.
Clue 2: If your intention is that previousNumber contains the number you are currently counting, then it needs to be initialized outside of the loop, and updates when the current number changes.
Clue 3: You should not increment sizeOfArray on every loop iteration ...
Based on your Question, I'd say that your thinking about / understanding of the code that you have written is woolly. And this is why you are having difficulty debugging it.
In order to debug a piece of code effectively, you first need a mental model of how it ought to work. Then you use the debugger to watch what is happening at key points to confirm that the program is behaving as you expect it to.
(If you come into the debugging process without a mental model, all you see is statements executing, variables changing, etcetera ... with nothing to tell you if the right thing is happening. It is like watching the flashing lights on a computer in an old movie ... not enlightening.)
I would opt for a hashmap where the key is the number and its value the count. This way you have a unique number and count. Your solution runs into a problem where you don't really know at index i, what count that number belongs to, unless your list has no duplicates and is in order with no gaps, like 1, 2, 3, 4, 5 as opposed to the case of 1, 1, 1, 1, 5, 5, 5, 5
HashMap<Integer, Integer> occurances = new HashMap>Integer, Integer>();
int[] someSortedArray = new int[10];
//fill up a sorted array
for(int index = 0; index < someSortedArray.length; index++)
{
someSortedArray[index] = index+1;
}
int current = someSortedArray[0];
int count = 1;
for(int index = 1; index < someSortedArray.length; index++)
{
if(someSortedArray[index] != current)
{
occurances.put(current, count);
current = someSortedArray[index];
count = 1;
}else
{
count++;
}
}
System.out.println(occurances);
I think this should do it (haven't compiled).
You where not increasing sizeOfArray anywhere in your for loop.
// Get the count of instances.
int[] countOfNumbers = new int[50]; // Array to store count
int sizeOfArray = 0; // Last position of array filled
int instanceCounter = 1; // Counts number of instances
int previousNumber = finalArrayOfNumbers[0]; // Number stored at [k-1]
for (int k=1; k < finalArrayOfNumbers.length; k++) {
if (previousNumber == finalArrayOfNumbers[k]) {
instanceCounter++;
}
else
{
countOfNumbers[sizeOfArray] = instanceCounter;
instanceCounter = 1;
sizeOfArray++;
previousNumber = finalArrayOfNumbers[k]
}
}
countOfNumbers[sizeOfArray] = instanceCounter;

Categories

Resources