Get largest and smallest group of ones in binary array - java

I have a 2D array of 0's and 1's.
Every consecutive cells having 1's is considered as single object.
My task is to find the largest consecutive 1's for every row and also smallest consecutive 1's and get the difference of those.
Example:
oth Row --> 0 0 0 0 0
1st Row --> 0 0 1 0 0
2nd Row --> 0 0 1 0 1
3rd Row --> 1 1 1 0 1
4th Row --> 0 0 0 0 0
Explanation:
In 0th Row there are no 1's so no operation needed.
In 1st Row there is a single 1, so I am considering it as largest object of this row is 1.
In 2nd Row there is a 1 at position [2,2], I am considering it as largest object of this row is 1. Now the next 1 at position [2, 4], I am considering it as smallest object of this row is 1.
In 3rd Row there are three 1's at position [3,0],[3,1],[3,2], I am considering it as largest object of this row is 3. Now the next 1 at position [3, 4], I am considering it as smallest object of this row is 1.
In 4th row there are no 1's so no operation needed.
My task is to find the difference between the sum all largest objects and sum of all smallest objects.
In this example:
Sum of largest objects = 0 (0th row) + 1 (1st row) + 1 (2nd row) + 3 (3rd row) + 0 (4th row) = 5
Sum of smallest objects = 0 (0th row) + 0 (1st row) + 1 (2nd row) + 1 (3rd row) + 0 (4th row) = 2
Result = sum of largest - sum of smallest = 5 - 2 = 3.
I have comeup with below logic:
public static int process(int[][] array)
{
int result = 0;
// Get row and column size
int rows = array.length;
int cols = array[0].length;
// variables to store sum of large and small objects
int large = 0;
int small = 0;
for(int i=0; i<rows; i++) {
// variables to store large and small objects per row level
int l_count = 0;
int s_count = 0;
boolean valid = false;
for(int j=0; j<cols-1; j++) {
int curr = array[i][j];
int next = array[i][j+1];
// First occurrence of 1 is considered as large object
if(l_count == 0 && curr == 1) {
l_count++;
valid = true;
}
// consecutive 1's added to large count
if(valid && curr == next) {
l_count++;
} else {
valid = false;
}
// Get small count
if(!valid && curr == 1 || next == 1) {
s_count++;
}
}
// Add row level counts to large and small objects
large += l_count;
small += s_count;
}
result = large - small;
return result;
}
This is not working and giving wrong results, I am not able to find the needed logic to solve this problem.

To find the largest and smallest objects in each row you might first want to get a list of all objects in the row, then filter accordingly, that is have a function that does
0 0 0 0 0 -> []
0 0 1 0 0 -> [1]
0 0 1 0 1 -> [1,1]
1 1 1 0 1 -> [3,1]
0 0 0 0 0 -> []
After that you can use a function such as Collections.max(collection) and Collections.min(Collection) to get the maximum and minimum values. To account for the case in row 1 you could then check if(foundObjects.size < 2) and set min to 0 in that case.
A possible implementation for this, assuming you are using Java 1.8 or newer would be the following:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
class ObjectCalculator {
static int compute(int[][] array){
return Arrays.stream(array)
.map(ObjectCalculator::findObjects)
.mapToInt(objects -> {
int min, max;
if (objects.size() < 2) min = 0;
else min = Collections.min(objects);
if (objects.size() < 1) max = 0;
else max = Collections.max(objects);
return max - min;
}).sum();
}
static List<Integer> findObjects(int[] array) {
ArrayList<Integer> objects = new ArrayList<>();
int curSize = 0;
for(int i : array){
if(i == 1)curSize++;
else if(curSize > 0){
objects.add(curSize);
curSize = 0;
}
}
if(curSize > 0){
objects.add(curSize);
}
return objects;
}
}

Perhaps the changes below could solve your problem. Do not look over to the next element, just keep a count and keep working with the current element always.
public static int process(int[][] array)
{
int result = 0;
// Get row and column size
int rows = array.length;
int cols = array[0].length;
// variables to store sum of large and small objects
int large = 0;
int small = 0;
for(int i=0; i<rows; i++) {
// variables to store large and small objects per row level
int l_count = 0;
int s_count = 0;
int count = 0;
for(int j=0; j<cols; j++) {
if (array[i][j]) {
count++;
} else if (count > 0) {
if (count > l_count) {
l_count = count;
} else if (count < s_count || s_count == 0) {
s_count = count;
}
count = 0;
}
}
// Add row level counts to large and small objects
large += l_count;
small += s_count;
}
result = large - small;
return result;
}

Related

Efficient way to solve subset sum variation

Given an integer array, find the maximum number of sums of adjacent elements that are divisible by n.
Example 1:
input: long[] array = [1, 2, 3], n = 7
output: 0
Example 2:
input: long[] array = [1, 2, 4], n = 7
output: 1
Example 3:
input: long[] array = [2, 1, 2, 1, 1, 2, 1, 2], n = 4
output: 6
Constraints:
array.length = 50000
array[index] <= 2^31 - 1
n <= 2^31 - 1
Currently, this is my code:
public static int maxSums(long[] array, long n) {
int count = 0;
if (array.length == 1 && array[0] == n) {
return 1;
} else {
for (int i = 0; i < array.length; i++) {
long sum = 0;
for (int j = i; j < array.length; j++) {
sum += array[j];
if (sum % n == 0) {
count++;
}
}
}
}
return count;
}
which is essentially the window sliding technique. However, this code runs with time complexity O(n^2) which is pretty slow, and results in Apex CPU Time Limit Exceeded towards the higher end of the constraints. Is there a faster way to solve this?
An approach I just thought of is O(n*m), where n is the actual n parameter and m is the array length.
The algorithm remembers for every subsequence up to the current index what reminder the sequence sum has. This information is stored inside the array called currentMod.
When iterating over the input array this currentMod is updated. We simply add to each possible modulo value of iteration i-1 the value of the input array at index i. The updated array includes the number of subsequence sums ending at index i for each possible reminder: 0, 1, 2 up to n-1.
The element first element of tmpMod at index i includes the number of subsequences that end at index i and have a sum divisible by n. Therefore, we add them to our final result.
Here is the algorithm:
public static int maxSums(int[] array, int n) {
int[] currentMod = new int[n];
int count = 0;
for (int i = 0; i < array.length; i++) {
// Add +1 to 0 remainder as a new sequence can start at every index which has sum 0
currentMod[0] += 1;
int[] tmpMod = new int[n];
for (int j = 0; j < currentMod.length; j++) {
// For every subsequence reminder of i-1 calculate the reminders of adding element i to every subsequence
tmpMod[(j + array[i]) % n] += currentMod[j];
}
// Add number of subsequence sums that divide by n with remainder 0 to result
count += tmpMod[0];
currentMod = tmpMod;
}
return count;
}
P.S.: This algorithm is not strictly better/worse than yours. It depends on another input value. This means it depends on your inputs what is more efficient. My algorithm is only better for a case with large arrays and low n values.
EDIT: After a lot of thinking and testing I think I found a good solution. It is O(n) in time complexity. It is also O(n) in space complexity as there can be at most n different remainders with n values in the array.
The algorithm keeps track of the current remainder, which is dividable by the input n from the start. For each new subsequence, we add the 1 at the current remainder. In this way, we already define which total sum (mod n) we need that the subsequence is dividable by n.
public static int maxSums(int[] array, int n) {
Map<Integer, Integer> currentMod = new HashMap<Integer, Integer>();
int count = 0;
int currentZero = 0;
for (int val : array) {
currentMod.put(currentZero, currentMod.getOrDefault(currentZero, 0) + 1);
currentZero = (currentZero + val) % n;
count += currentMod.getOrDefault(currentZero, 0);
}
return count;
}
Also, some comparisons to show that it should work out:
len(array)=50000 and n=1000:
Your method: 11704 ms
My old one: 188 ms
My new one: 13 ms
len(array)=50000 and n=1000000:
Your method: 555 ms
My old one: stopped after 2 minutes
My new one: 6 ms

I need help sorting an array in java based on frequency in this one particular way

need help taking an an array, counting frequency, putting in another array with array index acting at the number and individual value acting as the frequency in Java
You can sort a large array of m integers that are in the range 1 to n by using an array count of n
entries to count the number of occurrences of each integer in the array. For example, consider
the following array A of 14 integers that are in the range from 1 to 9 (note that in this case m =
14 and n = 9):
9 2 4 8 9 4 3 2 8 1 2 7 2 5
Form an array count of 9 elements such that count[i-1] contains the number of times that i
occurs in the array to be sorted. Thus, count is
1 4 1 2 1 0 1 2 2
In particular,
count[0] = 1 since 1 occurs once in A.
count[1] = 4 since 2 occurs 4 times in A.
count[2]=1 since 3 occurs once in A.
count[3] =2 since 4 occurs 2 times in A.
Use the count array to sort the original array A. Implement this sorting algorithm in the function
public static void countingSort(int[] a, int n )
and analyze its worst case running time in terms of m (the length of array a) and n.
After calling countingSort(), a must be a sorted array (do not store sorting result in a
temporary array).
edit:
this is what i've tried
public static void countingSort1(int[] a, int n) {
int [] temp = new int[n];
int [] temp2 = new int[n];
int visited = -1;
for (int index = 0; index < n; index++) {
int count = 1;
for (int j = index +1; j < n; j++) {
if(a[index] == a[j]) {
count++;
temp[j] = visited;
}
}
if (temp[index]!= visited) {
temp[index] = count;
}
}
for(int i = 1; i < temp.length; i++) {
if (temp[i] != visited) {
System.out.println(" " +a[i] + " | " +temp[i]);
}
}
Just to count the frequency but i think im doing it wrong
Something like below should do the work:
Since you already know what the highest value is, in yor example 9,
create a frequency array with space for nine elements.
iterate over your input array and for each value you find increase
the value at the index of the value in your frequency arra by one
create a counter for the index and initialize it with 0
iterate over your frequency array in a nested loop and replace the
values in your input array with the indexes of your frequency array.
I leave the analysis of the complexity to you
public static void countingSort(int[] a, int n ){
//counting
int[] freq = new int[n];
for(int i = 0; i<a.length; i++){
freq[a[i]-1]++;
}
//sorting
int index = 0;
for(int i = 0; i< freq.length; i++){
for(int j = 0;j < freq[i];j++){
a[index++]= i+1;
}
}
System.out.println(Arrays.toString(a));
}

Find maximal elements in array and delete all lines and columns that contain it

if we have these numbers in
array [][]
{1, 2, 3, 4},
{1, 2, 20, 4},
{1, 20, 2, 4},
{1, 2, 3, 4},};
it should looks like this
1 0 0 4
0 0 0 0
0 0 0 0
1 0 0 4
but i could output code only like this...
1 0 3 4
1 0 20 4
0 0 0 0
1 0 3 4
and i don't understand how to correct it, please help me,
this is my code.Thanks!
package com.company;
public class Main {
public static void main(String[] args) {
int[][] array2 = {{1, 2, 3, 4},
{1, 2, 20, 4},
{1, 20, 2, 4},
{1, 2, 3, 4},};
int countMax = 0;
int countIndexHorizontal = 0;
int countIndexVertical = 0;
int max = Integer.MIN_VALUE;
int m, k,x;
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
if (array2[i][j] > max) {
max = array2[i][j];
}
}
}
for (k = 0; k < array2.length; k++) {
for (m = 0; m < array2[k].length; m++) {
if (array2[k][m] == max) {
countIndexHorizontal = k;
countIndexVertical = m;
for (x = 0; x < array2.length; x++) {
for (int j = 0; j < array2[x].length; j++) {
if (countIndexVertical == x || j == countIndexHorizontal) {
array2[x][j] = 0;
}
}
}
}
}
}
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
System.out.print(array2[i][j] + " ");
}
System.out.println();
}
}
}
it looks like there are a lot of code and a little of words and site don't allow me to finally post my question and i'm really angry, maybe this text will help me to solve this problem.
Algorithm
This is the part when you only use pen and paper. Basically, I understood the problem as follow:
Given a matrix with n rows and m columns of Integer1:
Find the highest value
All entries in the rows and columns holding the highest value must have its value set at 0
Print the updated matrix
Assumption
I made the following assumptions:
In n is not necessarily equal to m. For example, you can have the array:
Valid Input
1 2 3 4 5 6
7 8 9 10 11 12
7 8 12 5 6 4
which must give, as 12 is the highest value:
Output
1 2 0 4 5 0
0 0 0 0 0 0
0 0 0 0 0 0
The matrix is consistent: every row has m columns and every column has n rows. For example, such input is incorrect:
Incorrect input
1 2 3
7 8 9 10
7 8
Logic
At this stage, you're still using pen, paper and Google only!
In my problem understanding, I splitted in three parts as I thought this is how you understood the problem. This is the mathematics understanding. Now let's convert it into a more Java understanding. First of all, we need to translate some vocabulary:
Mathematics wording | Java wording
--------------------|---------------------
matrix | 2-dimensional array
Integer | int (primitive type)
which gives in Java way:
Given an 2-dimensional int[][] array:
Find the highest value
Find the rows and columns holding the highest value
Update the array by setting the value to 0 for the rows and columns found in 2.
Print the array
In the specific case of my solution, I combine 1. + 2. and I combined 3. + 4.
What you did
Let's open your favorite IDE and compare my analysis with your input:
Find the highest value: OK here: : you use the variable max and scan the matrix to find the maximum value. You also assumed that the matrix could be rectangle (n rows and m columns with n != m). So it's good
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
if (array2[i][j] > max) {
max = array2[i][j];
}
}
}
Find the rows and columns: ERROR here, as mentioned by ccp-beginner, when you found a the highest value, you erase (set to zero) the value for the whole column and whole row but maybe the same highest value was stored somewhere else in this row or column
for (k = 0; k < array2.length; k++) {
for (m = 0; m < array2[k].length; m++) {
if (array2[k][m] == max) {
countIndexHorizontal = k;
countIndexVertical = m;
// additional operation defined in 3.
}
// in ccp-beginner example of
// 2, 2
// 1, 1
// if k=0 and m=0, you'll update the value
// of the first row and first column giving:
// 0, 0
// 0, 1
// but when k=0, m=1, you'll find 0 instead
// of 2 so your program will consider that
// this row / column does not contain the
// highest value
}
}
I assume here the
countIndexHorizontal = row
countIndexVertical = column
So you need to keep track of the rows and columns when you're setting the values to 0.
Update the array: ERROR here (cf ccp-beginner's answer)
for (x = 0; x < array2.length; x++) {
for (int j = 0; j < array2[x].length; j++) {
if (countIndexVertical == x || j == countIndexHorizontal) {
array2[x][j] = 0;
// In your example:
// 1 2 3 4
// 1 2 20 4
// 1 20 2 4
// 1 2 3 4
// and if countIndexVertical=2 and countIndexHorizontal=1
// (the 20 of the second row between 2 and 4), you'll have
// 1 0 3 4
// 1 0 20 4
// 0 0 0 0
// 1 0 3 4
// instead of
// 1 2 0 4
// 0 0 0 0
// 1 20 0 4
// 1 2 0 4
}
}
}
you got confused between countIndexVertical and countIndexHorizontal, as you have
x = row
j = column
You should had (please notice the swapping)
if (countIndexHorizontal == x || j == countIndexVertical) {
array2[x][j] = 0;
}
Print the array: OK here, nothing special to mention
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
System.out.print(array2[i][j] + " ");
}
System.out.println();
}
The problem
Basically, what you need is how to store the rows and the columns containing the highest value. At first, we could be tempted to use array again right, like
int[] rowsContainingHighestValue;
int[] columnsContainingHighestValue;
But you don't know how many highest value you'll encounter so you need something to store multiple value with a dynamic size: I'll use List.
Some Java point
The rowsContainingHighestValue and columnsContainingHighestValue become:
List<Integer> rowsContainingHighestValue = new ArrayList<>();
List<Integer> columnsContainingHighestValue = new ArrayList<>();
You may want to have a look at the following point:
Why List instead of array?
My objects are declared as List but I instantiate2 with ArrayList: What is a Interface and what is a Class
Why I used List<Integer> instead of List<int>
What is the difference between Integer and int
One solution
loop through for the matrix to fetch the maximum value and store all rows and columns holding this value instead of a single row/column combination (countIndexHorizontal and countIndexVertical)
If a new maximum value is found, store it (like you did) AND store the current row and column index
If a value is identical to the current maximum value (e.g. you have 20 twice), then append the row and column index to the existing respective row / column list
loop a second time for updating and printing the value
it's basically combining your two last double-loop: if the scanned element belongs to a row or a column holding the maximum value, then the value must be set at 0 (exactly the way you did but shorter as I already have the list of rows / columns)
once the values are properly updated, just proceed to a simple printing
Which in code gives:
public static void main(String[] args) {
int[][] array2 = {
{1, 2, 3, 4},
{1, 2, 20, 4},
{1, 20, 2, 4},
{1, 2, 3, 4}
};
// find the maximum value and store its position:
// It's List instead of a single value as multiple
// rows and columns can hold the same maximum value
List<Integer> rowsWithMaxValue = new ArrayList<>();
List<Integer> colsWithMaxValue = new ArrayList<>();
int maxValue = Integer.MIN_VALUE;
// First matrix-scan to fetch the maximum value and the
// row(s) and column(s) to set the value at 0
for (int row = 0; row < array2.length; row++) {
for (int col = 0; col < array2[row].length; col++) {
// get the current value
int value = array2[row][col];
// found a new maximum or an existing one?
if (value > maxValue) {
// this is a new maximum value, we can reset
// the list as the previous rows and columns
// are not relevant anymore
maxValue = value;
rowsWithMaxValue = new ArrayList<>();
colsWithMaxValue = new ArrayList<>();
rowsWithMaxValue.add(row);
colsWithMaxValue.add(col);
} else if (value == maxValue) {
// The same value (like 20) is found again
// so multiple rows and columns will have
// their value set at 0
rowsWithMaxValue.add(row);
colsWithMaxValue.add(col);
}
}
}
// Second matrix-scan for updating the values and printing
for (int row = 0; row < array2.length; row++) {
for (int col = 0; col < array2[row].length; col++) {
// is it in a forbidden row? If yes, set the value
// at zero. One of the condition (row or column) is
// enough to have its value set at 0
if (rowsWithMaxValue.contains(row) || colsWithMaxValue.contains(col)) {
array2[row][col] = 0;
}
// Simply print the value
System.out.print(array2[row][col] + " ");
}
System.out.println();
}
}
1Integer in the mathematics meaning: positive or negative number without decimal
2I won't explain instantiation here. Feel free to google it
You can improve the program by changing the condition to
if (countIndexHorizontal == x || j == countIndexVertical)
Your program is deleting the wrong lines for the first 20 it finds (including the other 20).
This change will get you the correct answer for your specific case, but the program is still broken for examples like this
2 2
1 1
The correct output is
0 0
0 0
but it won't work because when it finds the first 2 it will delete the second 2, but the second 2 is still needed to clear the 0 in the bottom right corner. You're going to have to keep a separate data structure for the positions you want to clear. I'll leave that for you to figure out.

Generate 10 random pairs conditionally

I have the following for loop which is supposed to generate two random integers and call grid.place(x,y). I'm trying to figure out how to generate a different pair if grid.place(x,y) returns false. The place method returns true if the provided x and y where not previously provided. Thank you.
for (int i = 0; i < 10; i++) {
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
grid.place(mx,my);
}
This is the perfect situation for a do-while loop:
for (int i = 0; i < 10; i++) {
do{
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
}while(!grid.place(mx,my));
}
Another solution would be to make use of the Collections.shuffle() method. like so:
List<Integer> xPos = IntStream.rangeClosed(0,10).boxed().collect(Collectors.toList());
List<Integer> yPos = IntStream.rangeClosed(0,10).boxed().collect(Collectors.toList());
Collections.shuffle(xPos);
Collections.shuffle(yPos);
for(int i=0;i<10;i++)
grid.place(xPos.get(i), yPos.get(i));
This will give you all coords and never repeat in better complexity than the do-while loop
To avoid duplicate, you can use a List for example :
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);//fill your list
}
Random randomGenerator = new Random();
int mx = randomGenerator.nextInt(10);//generate the first value
int x = mx;//to not lost this value we store it in another variable
list.remove(mx);//remove the first value from your list, to avoid duplicate
int my = randomGenerator.nextInt(9);//generate the second value
int y = my;
grid.place(x, y);//now, you are sure that you have two different values
Here is a more OO like approach:
Most likely the "grid" is not infinite. This means you can create a list of all possible positions in the grid:
class Position{
private final int x;
private final int y;
public Position(int x, int y){
this.x=x;
this.y=y;
}
public getX(){return x;}
public getY(){return y;}
}
List<Position> availablePositions = new ArrayList<>();
for(int i =0; i<MAX_X;i++)
for(int j =0; j<MAX_Y;j++)
availablePositions.add(new Position(i,j));
Then you can retrieve a random index from that list:
for (int i =0;i<10;i++){
Position randomPosition =
availablePositions.remove(
new Random().nextInt(availablePositions.size()));
grid.place(
randomPosition.getX(),
randomPosition.getY());
}
This way you will never get a duplicate, but the positions taken are lost for the programs current execution.
alternatively you can just shuffle the list and take the first 10 elements:
Collections.shuffle(availablePositions);
for (int i =0;i<10;i++)
grid.place(
availablePositions.get(i).getX(),
availablePositions.get(i).getY());
This also ensures distinct positions within the loop but you keep all positions in the list for later use...
My biggest problem with this solution is that it has deterministic time at the cost of O(MAX_X * MAX_Y) memory. Other solutions have O(1) time (for small values of i), though not deterministic, and O(1) memory. – gobernador
On modern computers memory is not the limiting resource (not even on cell phones...). When programming in Java, you should not optimize for memory and/or Performance unless you have proven you have a problem. And if you really have a memory problem then Java is most likely the wrong tool for the task.
But:
When we accept some more OO in the solution then we would not need separate
Position objects waisting memory. We could rather have Cell objects with a state we can change instead of immutable String objects in the grid. Working with a custom class as elements in the grid has some more advantages aside from enabling this selection mechanism, so we should have a look at it.
Cell.java
class Cell{
private String content = " "; // empty
public void placeHere(String newContent){
content = newContent;
}
}
Grid.java
// ...
Cell[][] gameField = new Cell[MAX_X][MAX_Y];
for(int i =0; i
Then we can collect this existing cells in a separate List:
List allCells = new ArrayList<>();
for(Cell[] row : gameField)
allCells.addAll(Arrays.asList(row));
And select random cells to change the state:
Collections.shuffle(allCells);
for(int i =0; i<10; i++)
allCells.get(i).placeHere("*");
Actually we don't even need to know the changed cells coordinates. And that is what OOP is about: solve your task with as less technical knowledge in your code as possible.
And wait, there is more:
How do you reset the game with the pure String array? Right, you iterate over the complete array. but the best performance optimisation hint I ever got is:
the fastest way to do something is not to do it.
So how can we avoid the iteration over the complete Array?
With my approach we can collect the modified cells in a separate list:
List<Cell> modifiedCells = new ArrList<>();
Collections.shuffle(allCells);
for(int i =0; i<10; i++){
Cell currentCell = allCells.get(i);
currentCell.placeHere("*");
modifiedCells.add(currentCell);
}
Then you have to reset 10 cell objects in that extra list instead of MAX_X*MAX_Y strings in an array.
You could do
for(int i = 0; i < 10; i++){
while(true){
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
if(grid.place(mx,my)) break;
}
}
This while loops over, until grid#place returns true, and keeps generating random values.
The longest and most brute-force way to approach this is to check if the coordinates already have been accessed in the grid.
You would have to start with ten and work your way down to zero.
int size = 10;
for (int count = size; count > 0;) {
mx = randomGenerator.nextInt(size);
my = randomGenerator.nextInt(size);
if (!grid.exists(mx, my)) {
grid.place(mx, my);
count--;
}
}
Example
public class Grid {
private boolean[][] self;
public Grid(int size) {
this.self = new boolean[size][size];
}
public int getSize() {
return this.self.length;
}
public boolean exists(int row, int col) {
return this.self[row][col];
}
public void place(int row, int col) {
this.self[row][col] = true;
}
#Override
public String toString() {
StringBuffer buff = new StringBuffer();
for (int row = 0; row < this.self.length; row++) {
if (row > 0) {
buff.append(System.lineSeparator());
}
for (int col = 0; col < this.self[0].length; col++) {
if (col > 0) {
buff.append('\t');
}
buff.append(this.self[row][col] ? '1' : '0');
}
}
return buff.toString();
}
}
public class GridDriver {
public static void main(String[] args) {
int size = 10;
Grid grid = new Grid(size);
for (int count = size; count > 0;) {
int mx = (int) (Math.random() * size);
int my = (int) (Math.random() * size);
if (!grid.exists(mx, my)) {
grid.place(mx, my);
count--;
}
}
System.out.println(grid);
}
}
Output
0 0 0 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 1 1 0
0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 1
The best way to solve this would be to create some type of memory map and generate permutations and randomly iterate over those values.
If you need to keep trying generate numbers until its gonna be placed, and fill grid 10x10, basically all you want to do is to check for already placed numbers.
Set<Integer> placedNumbers = new HashSet<>();
while(set.size() != 100) {
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
if(!placedNumbers.contains(mx+my) && grid.place(mx,my)) {
placedNumbers.add(mx+my);
}
}
You just need to check that whichever pair you are passing that is not passed previously.
Using HashSet you can achieve it:
HashSet<String> set = new HashSet<>();
int i = 0;
while(i<10) {
mx = randomGenerator.nextInt(10);
my = randomGenerator.nextInt(10);
String rand = mx + "" + my;
if(!set.add(rand)){
grid.place(mx,my);
i++;
}
}
So set will ensure that whatever pair you are passing, that is not passed previously.

in Java, design linear algorithm that finds contiguous subsequence with highest sum

this is the question, and yes it is homework, so I don't necessarily want anyone to "do it" for me; I just need suggestions: Maximum sum: Design a linear algorithm that finds a contiguous subsequence of at most M in a sequence of N long integers that has the highest sum among all such subsequences. Implement your algorithm, and confirm that the order of growth of its running time is linear.
I think that the best way to design this program would be to use nested for loops, but because the algorithm must be linear, I cannot do that. So, I decided to approach the problem by making separate for loops (instead of nested ones).
However, I'm really not sure where to start. The values will range from -99 to 99 (as per the range of my random number generating program).
This is what I have so far (not much):
public class MaxSum {
public static void main(String[] args){
int M = Integer.parseInt(args[0]);
int N = StdIn.readInt();
long[] a = new long[N];
for (int i = 0; i < N; i++) {
a[i] = StdIn.readLong();}}}
if M were a constant, this wouldn't be so difficult. For example, if M==3:
public class MaxSum2 {
public static void main(String[] args){
int N = StdIn.readInt(); //read size for array
long[] a = new long[N]; //create array of size N
for (int i = 0; i < N; i++) { //go through values of array
a[i] = StdIn.readLong();} //read in values and assign them to
//array indices
long p = a[0] + a[1] + a[2]; //start off with first 3 indices
for (int i =0; i<N-4; i++)
{if ((a[i]+a[i+1]+a[1+2])>=p) {p=(a[i]+a[i+1]+a[1+2]);}}
//if sum of values is greater than p, p becomes that sum
for (int i =0; i<N-4; i++) //prints the subsequence that equals p
{if ((a[i]+a[i+1]+a[1+2])==p) {StdOut.println((a[i]+a[i+1]+a[1+2]));}}}}
If I must, I think MaxSum2 will be acceptable for my lab report (sadly, they don't expect much). However, I'd really like to make a general program, one that takes into consideration the possibility that, say, there could be only one positive value for the array, meaning that adding the others to it would only reduce it's value; Or if M were to equal 5, but the highest sum is a subsequence of the length 3, then I would want it to print that smaller subsequence that has the actual maximum sum.
I also think as a novice programmer, this is something I Should learn to do. Oh and although it will probably be acceptable, I don't think I'm supposed to use stacks or queues because we haven't actually covered that in class yet.
Here is my version, adapted from Petar Minchev's code and with an important addition that allows this program to work for an array of numbers with all negative values.
public class MaxSum4 {
public static void main(String[] args)
{Stopwatch banana = new Stopwatch(); //stopwatch object for runtime data.
long sum = 0;
int currentStart = 0;
long bestSum = 0;
int bestStart = 0;
int bestEnd = 0;
int M = Integer.parseInt(args[0]); // read in highest possible length of
//subsequence from command line argument.
int N = StdIn.readInt(); //read in length of array
long[] a = new long[N];
for (int i = 0; i < N; i++) {//read in values from standard input
a[i] = StdIn.readLong();}//and assign those values to array
long negBuff = a[0];
for (int i = 0; i < N; i++) { //go through values of array to find
//largest sum (bestSum)
sum += a[i]; //and updates values. note bestSum, bestStart,
// and bestEnd updated
if (sum > bestSum) { //only when sum>bestSum
bestSum = sum;
bestStart = currentStart;
bestEnd = i; }
if (sum < 0) { //in case sum<0, skip to next iteration, reseting sum=0
sum = 0; //and update currentStart
currentStart = i + 1;
continue; }
if (i - currentStart + 1 == M) { //checks if sequence length becomes equal
//to M.
do { //updates sum and currentStart
sum -= a[currentStart];
currentStart++;
} while ((sum < 0 || a[currentStart] < 0) && (currentStart <= i));
//if sum or a[currentStart]
} //is less than 0 and currentStart<=i,
} //update sum and currentStart again
if(bestSum==0){ //checks to see if bestSum==0, which is the case if
//all values are negative
for (int i=0;i<N;i++){ //goes through values of array
//to find largest value
if (a[i] >= negBuff) {negBuff=a[i];
bestSum=negBuff; bestStart=i; bestEnd=i;}}}
//updates bestSum, bestStart, and bestEnd
StdOut.print("best subsequence is from
a[" + bestStart + "] to a[" + bestEnd + "]: ");
for (int i = bestStart; i<=bestEnd; i++)
{
StdOut.print(a[i]+ " "); //prints sequence
}
StdOut.println();
StdOut.println(banana.elapsedTime());}}//prints elapsed time
also, did this little trace for Petar's code:
trace for a small array
M=2
array: length 5
index value
0 -2
1 2
2 3
3 10
4 1
for the for-loop central to program:
i = 0 sum = 0 + -2 = -2
sum>bestSum? no
sum<0? yes so sum=0, currentStart = 0(i)+1 = 1,
and continue loop with next value of i
i = 1 sum = 0 + 2 = 2
sum>bestSum? yes so bestSum=2 and bestStart=currentStart=1 and bestEnd=1=1
sum<0? no
1(i)-1(currentStart)+1==M? 1-1+1=1 so no
i = 2 sum = 2+3 = 5
sum>bestSum? yes so bestSum=5, bestStart=currentStart=1, and bestEnd=2
sum<0? no
2(i)-1(currentStart)+1=M? 2-1+1=2 so yes:
sum = sum-a[1(curentstart)] =5-2=3. currentStart++=2.
(sum<0 || a[currentStart]<0)? no
i = 3 sum=3+10=13
sum>bestSum? yes so bestSum=13 and bestStart=currentStart=2 and bestEnd=3
sum<0? no
3(i)-2(currentStart)+1=M? 3-2+1=2 so yes:
sum = sum-a[1(curentstart)] =13-3=10. currentStart++=3.
(sum<0 || a[currentStart]<0)? no
i = 4 sum=10+1=11
sum>bestSum? no
sum<0? no
4(i)-3(currentStart)+1==M? yes but changes to sum and currentStart now are
irrelevent as loop terminates
Thanks again! Just wanted to post a final answer and I was slightly proud for catching the all negative thing.
Each element is looked at most twice (one time in the outer loop, and one time in the while loop).
O(2N) = O(N)
Explanation: each element is added to the current sum. When the sum goes below zero, it is reset to zero. When we hit M length sequence, we try to remove elements from the beginning, until the sum is > 0 and there are no negative elements in the beginning of it.
By the way, when all elements are < 0 inside the array, you should take only the largest negative number. This is a special edge case which I haven't written below.
Beware of bugs in the below code - it only illustrates the idea. I haven't run it.
int sum = 0;
int currentStart = 0;
int bestSum = 0;
int bestStart = 0;
int bestEnd = 0;
for (int i = 0; i < N; i++) {
sum += a[i];
if (sum > bestSum) {
bestSum = sum;
bestStart = currentStart;
bestEnd = i;
}
if (sum < 0) {
sum = 0;
currentStart = i + 1;
continue;
}
//Our sequence length has become equal to M
if (i - currentStart + 1 == M) {
do {
sum -= a[currentStart];
currentStart++;
} while ((sum < 0 || a[currentStart] < 0) && (currentStart <= i));
}
}
I think what you are looking for is discussed in detail here
Find the subsequence with largest sum of elements in an array
I have explained 2 different solutions to resolve this problem with O(N) - linear time.

Categories

Resources