I have a task.I need to find the biggest area with equal numbers(e.g. neighbours by row or column). The program that i made works fine,but the problem is that if i have the following matrix:
{ 1, 3, 2, 2, 2, 4 }
{ 3, 1, 3, 2, 4, 4 }
{ 4, 3, 1, 2, 3, 3 }
{ 4, 3, 1, 3, 3, 1 }
{ 4, 3, 3, 3, 1, 1 }
The program will print 10.Okay maybe some of you may say that it's because i add 1 to the final result,yeah that's true but if i don't add 1 ,and if the number at position [1][1] was 3 instead of 1 ,i would get 12 witch is wrong,so that`s why i add 1.So my question is do you have any suggestions about optimazing the algorithm..if yes,i would be very thankful to hear them :)..
Here is my code:
protected int counter = 0;
protected int max = 1;
protected enum eState {
Vi,
InPr,
Unvi
};
public void recNodeMatrix(int i, int j, eState st[][],int [][]matr,int n,int k) {
st[i][j] = eState.InPr;
for (int r = 0; r < n; r++) {
for (int c = 0; c < k; c++) {
if ((matr[i][j] == matr[r][c])
&& ((((i+j) - (r + c)) == 1) || (((i+j) - (r + c)) == -1))
&& ((st[r][c] == eState.Unvi))) {
counter++;
recNodeMatrix(r, c, st,matr,n,k);
}
}
}
st[i][j] = eState.Vi;
}
public void Zad17() {
int n=5,k=6;
eState st[][] = new eState[n][k];
int[][] matr = new int[][] {
{ 1, 3, 2, 2, 2, 4 },
{ 3, 1, 3, 2, 4, 4 },
{ 4, 3, 1, 2, 3, 3 },
{ 4, 3, 1, 3, 3, 1 },
{ 4, 3, 3, 3, 1, 1 } };
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
st[i][j] = eState.Unvi;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
if(st[i][j] == eState.Unvi) {
recNodeMatrix(i, j, st,matr,n,k);
if(max<counter)
max=counter;
counter =0;
}
}
}
System.out.print(max+1);
}
Probably the best way to solve this problem is with a union-find data structure: https://en.wikipedia.org/wiki/Disjoint-set_data_structure
Initially, each cell is its own set, and then you merge the sets for every pair of adjacent cells that have equal numbers in them.
When you're done, the answer is the size of the biggest set. Since you have to keep track of the set sizes anyway, use union-by-size instead of union-by-rank.
Applying a bit of cleverness, you can implement the union-find with just an array of N*K integers -- one for each cell. Each integer is either the index of the parent set or -size for roots.
This solves the problem in about linear time, and will probably be faster in practice than flood-fill solutions using a similar amount of memory.
Related
Given a provided array, determine how many groups of a specified size exist.
For the array [1,1,1,2,2,2,3,3,3,4,5,6,7] , there are 7 groups with at least one, 3 groups with at
least 2, and 3 groups with at least 3. A group is a series of same values. 1 1 1 is a group of 3, but it also is
a group of 1 and 2. To count as a group, all values must be the same. 1 1 1 is a group of 3 because there
are 3 1s in a row.
Sample output:
[3, 3, 3, 3, 3, 9, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8]
size 1 count == 7
size 2 count == 6
size 3 count == 5
size 4 count == 3
size 5 count == 2
size 6 count == 1
My main code:
import static java.lang.System.*;
import java.util.Arrays;
import java.util.Scanner;
import static java.lang.System.*;
import java.util.Arrays;
import java.util.Scanner;
public class ArrayStats {
int[] numArray;
int number;
public ArrayStats(int[] a) {
setArray(a);
}
public void setArray(int[] a) {
numArray = a;
}
public int getNumGroupsOfSize() {
int cnt = 0;
for (int i = 0; i < numArray.length - 1; i++) {
if (numArray[i] == numArray[i + 1])
cnt++;
for (int j = 0; j <= 9; j++) {
if (cnt == i)
number = cnt;
else if (cnt == 1)
number = 1;
}
}
return number;
}
public String toString() {
return "size count" + " == " + getNumGroupsOfSize() + Arrays.toString(numArray);
}
}
My runner code:
public class ArrayStatsRunner
{
public static void main(String args[])
{
int[] one = {3, 3, 3, 3, 3, 9, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8};
ArrayStats test = new ArrayStats(one);
System.out.println(test.toString());
System.out.println("size 1 count == "+test.getNumGroupsOfSize(1));
System.out.println("size 2 count == "+test.getNumGroupsOfSize(2));
System.out.println("size 3 count == "+test.getNumGroupsOfSize(3));
System.out.println("size 4 count == "+test.getNumGroupsOfSize(4));
System.out.println("size 5 count == "+test.getNumGroupsOfSize(5));
System.out.println("size 6 count == "+test.getNumGroupsOfSize(6));
}
}
There is couple of problems with this method:
public int getNumGroupsOfSize() {
int cnt = 0;
for (int x = 0; x < numArray.length - 1; x++) {
if (numArray[x] == numArray[x + 1]);
cnt++;
for (int y = 2; y <= 9; y++) {
if (cnt == y)
number = cnt;
else if (cnt == 1)
number = 1;
}
}
return number;
}
Here is only some of the problems:
1. lets look at the second line:
for (int x = 0; x < numArray.length - 1; x++)
x < numArray.length - 1 will cause a problem because you wont check the last index of the array.
side note: it's a custom to use the letter i (index) and not x or y. If you are doing for loop inside for loop the custom is to do:
for (int i = 0; i < numArray.length - 1; i++)
{
for (int j = 0; j < numArray.length - 1; j++)
{
//some line of code
}}
This line of code if (numArray[x] == numArray[x + 1]);will do nothing because you put ; in the end of the row. Even if numArray[x] == numArray[x + 1]is true it wont do cnt++;.
Please check and learn from this code:
public class Main {
public static void main(String [] args)
{
int[] nums = {3, 3, 3, 3, 3, 9, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8};
System.out.println(+getGroupSize(nums,9)); //prints 1
System.out.println("size two== "+groupCount(nums,2)); //prints 6
System.out.println("size three== "+groupCount(nums,3));//prints 5
int[] nums2={1,1,1,2,2,2,3,3,3,4,5,6,7};
System.out.println(+getGroupSize(nums2,1)); //prints 3
System.out.println("size two== "+groupCount(nums2,2)); //prints 3
System.out.println("size two== "+groupCount(nums2,3)); //prints 3
System.out.println("size two== "+groupCount(nums2,5)); //prints 0
}
public static int getGroupSize(int[] array, int specificNumber ) {
/*This method prints the number of times a specific number exist in a array.
example: if the input of specificNumber is 3. in this array:
int[] nums = {3, 3, 3, 3, 3, 9, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8};
the method will return 5.
if the number is 9 is method will return 1. if number is 7 the method will return 3
*/
int groupCount = 0; //counts the number of times a specific number exist in a array
for (int i = 0; i <= array.length - 1; i++) { //this for loop will check every number in array
if (array[i] ==specificNumber) {
groupCount++;// if the current number of the array is the specificNumber, then the count will do plus one
}
}
return groupCount; //return the count
}
public static int groupCount(int[] array, int groupSize)
{
int groupCount=0;
int currentGroup=array[0]; //initialize the current group to be the first group of the array
if(getGroupSize(array, array[currentGroup])>=groupSize)
{ //check the size of the first group
groupCount++;
}
for (int i = 0; i <= array.length - 1; i++) {
if (array[i] !=currentGroup) { //checks if the current number is equal to the current group value
if(getGroupSize(array, array[i])>=groupSize)
{
groupCount++;
}
currentGroup=array[i]; // restart the currentGroup to be the current valume of the array
}
} //end of for loop
return groupCount;
}
private static void print(int [] array) {
for (int i = 1; i < 10; i++) {
System.out.println("size " +i+" group:" +groupCount(array, i));
}
}
}
So, basically it's the same idea as the subset sum problem, but with one restriction: The found subset needs to have an even size.
For example:
numbers {4, 3, 3, 5, 1, 2, 7, 12}
find subset that sums up to 10
=> solution: {4, 3, 1, 2} (or {3, 7} but not {4, 3, 3} )
Is there a simple method to find such a subset? (The method should be "efficient", not just trying all possible subsets...)
Here is my code to find a "normal" subset:
int n = 8;
int m = 11;
boolean[][] S = new boolean[n][m];
int[] N = new int[] {4, 3, 3, 5, 1, 2, 7, 12};
S[0][0] = true;
S[0][S[0]] = true;
for(int i = 1; i < n; i++) {
for(int j = 0; j < m; j++) {
if(N[i] == j) {
S[i][j] = true;
} else if(j - N[i] >= 0) {
S[i][j] = S[i-1][j] || S[i-1][j - N[i]];
} else {
S[i][j] = S[i-1][j];
}
}
}
In your current code S[i][j] is true if you can make value j as a subset of numbers up to i.
Instead, compute S[i][j][k] is true if you can make value j as a subset of numbers up to i with the number of numbers used equal to k modulo 2.
In other words, k is either 0 or 1.
This will require around twice the computations of your existing solution.
I'm quite new to Java but I've got the basics...
So I have an array of 4 ints which I need to move to the front of the array, or merge them if they are equal so:
{0,1,0,2} turns into {1,2,0,0}
{2,1,0,2} turns into {2,1,2,0}
{1,1,0,0} turns into {2,0,0,0}
{0,2,0,2} turns into {4,0,0,0}
{1,1,3,3} turns into {2,6,0,0}
{2,2,2,2} turns into {4,4,0,0} etc...
Here's what I have so far:
public void combine(int[] row)
{
for (int i = 0; i < row.length-1; i++)
{
if (row[i] == 0 && row[i+1] > 0) //move
{
row[i] = row[i+1];
row[i+1] = 0;
}
if (row [i] == row[i+1] && row[i] > 0) //merge
{
row[i] = 2 * row[i];
row[i+1] = 0;
}
}
System.out.println(row[0]);
System.out.println(row[1]);
System.out.println(row[2]);
System.out.println(row[3]);
}
The problem is:
{0,1,0,2} becomes {1,0,2,0}
{0,2,0,2} becomes {2,0,2,0}
{1,1,3,3} becomes {2,3,3,0}
{2,2,2,2} becomes {4,2,2,0}
It doesn't merge fully, or it only moves and merges once for some reason? I would like to know what I am doing wrong so I can learn, thanks!
Please, could anyone help me with this? I would really appreciate it... Thanks!
It appears that you will need to perform a move to front, then merge your elements and then move to front again. The merge is relatively simple to implement, examine even indexes in the array; if two adjacent elements are equal multiply one by two and set the other to 0. Something like,
private static void merge(int[] arr) {
for (int i = 0; i + 1 < arr.length; i += 2) {
if (arr[i] == arr[i + 1]) {
arr[i] *= 2;
arr[i + 1] = 0;
}
}
}
I would begin with swap, to move elements in the array like
private static void swap(int[] arr, int i, int j) {
if (i == j) {
return;
}
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
Then for move to front, examine each element from the left; when we get a 0 begin looking from the right for a non-zero and then swap
private static void moveToFront(int[] arr) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
for (int j = arr.length - 1; j > i; j--) {
if (arr[j] != 0) {
swap(arr, i, j);
}
}
}
}
}
Next, combine; move to front, merge and then move to front again
public static void combine(int[] row) {
moveToFront(row);
merge(row);
moveToFront(row);
}
Finally, we can test it like
public static void main(String[] args) {
int[][] arr = { { 0, 1, 0, 2 }, // turns into {1,2,0,0}
{ 2, 1, 0, 2 }, // turns into {2,1,2,0}
{ 1, 1, 0, 0 }, // turns into {2,0,0,0}
{ 0, 2, 0, 2 }, // turns into {4,0,0,0}
{ 1, 1, 3, 3 }, // turns into {2,6,0,0}
{ 2, 2, 2, 2 } };// turns into {4,4,0,0}
for (int[] a : arr) {
combine(a);
System.out.println(Arrays.toString(a));
}
}
And I get (as requested)
[1, 2, 0, 0]
[2, 1, 2, 0]
[2, 0, 0, 0]
[4, 0, 0, 0]
[2, 6, 0, 0]
[4, 4, 0, 0]
The problem is the move and merge in your code is only 1-step moving, while the move and merge could be 2 or more steps moving. This is not a java question but a algorithm one.
This is a two-pointer question by using i and j, i is to record the position you are going to move number in and j is the position you have reached out to the furthest to get number from.
This question already has answers here:
How to find 3 numbers in increasing order and increasing indices in an array in linear time
(14 answers)
is it possible to find all the triplets in the given array for the O (n) time?
(1 answer)
Closed 6 years ago.
A decreasing triple is defined as a set of 3 values {a, b, c} that decrease in magnitude from left to right such that a > b > c.
How could one find the number of these triples in an array of integers where the indices of the triple {i, j, k} are increasing such that i < j < k.
For example, consider the following examples:
{4, 5, 2, 1}
2 decreasing triples: {4, 2, 1} and {5, 2, 1}
{6, 1, 2, 4, 5, 3}
2 decreasing triples: {6, 5, 3} and {6, 4, 3}
{5, 4, 3, 2, 1}
10 decreasing triples:
{5, 4, 3}, {5, 4, 2}, {5, 4, 1}, {5, 3, 2}, {5, 3, 1},
{5, 2, 1}, {4, 3, 2}, {4, 3, 1}, {4, 2, 1}, {3, 2, 1}
The O(n^3) solution is trivial of course; here is an implementation in java:
*note: the arrays are of longs, but that is a minor implementation detail
public static long countTriples(long[] measurements)
{
// O(n^3)
long count = 0L;
for(int i = 0; i < measurements.length; i++)
{
for(int j = i + 1; j < measurements.length; j++)
{
if ( measurements[j] < measurements[i] )
{
for(int k = j + 1; k < measurements.length; k++)
{
if ( measurements[k] < measurements[j] )
{
count++;
}
}
}
}
}
return count;
}
}
I began an O(n) method to locate decreasing triples; it successfully identified triples, but I couldn't get it to count right when the middle value of a given triple was involved in more than one. Here is what I have of that right now:
public static long countTriples(long[] measurements)
{
ArrayList<Long> greaterOnLeft = new ArrayList<Long>();
ArrayList<Long> lessOnRight = new ArrayList<Long>();
HashSet<Long> min = new HashSet<Long>();
min.add(measurements[measurements.length - 1]);
HashSet<Long> max = new HashSet<Long>();
max.add(measurements[0]);
for(int i = 0; i < measurements.length; i++)
{
min.add(measurements[measurements.length - i - 1]);
max.add(measurements[i]);
System.out.println("max: " + max + ", min: " + min);
for(long n : max)
if (measurements[i] < n) greaterOnLeft.add(measurements[i]);
for(long n : min)
if (measurements[measurements.length - i - 1] > n) lessOnRight.add(measurements[measurements.length - i - 1]);
}
long count = 0;
for(long n : greaterOnLeft)
{
if(lessOnRight.contains(n)) count++;
}
return count;
}
The idea for this approach came from a HashSet method for locating the middle indices of such tripples from this post:
How to find 3 numbers in increasing order and increasing indices in an array in linear time
I believe this can be solved in O(n^2) time rather trivially:
public static long countTriples(long[] measurements)
{
// O(n^2)
long count = 0;
for(int i = 1; i < measurements.length - 1; i++)
{
long right = 0, left = 0;
for(int j = 0; j < measurements.length; j++)
{
if(j < i && measurements[j] > measurements[i]) right++;
else if (j > i && measurements[j] < measurements[i]) left++;
}
count += right * left;
}
return count;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
So I can just use standard arrays for this, nothing else. I have to find a way to make a method that finds all the cycles in the given permutation and returns them as an array object of arrays. Then I have to place the lowest of each array as the first entry of the array. Then sort them by lowest.
I can't use arraylists or sets or anything.
EDIT: By cycles I mean take the integer value of the initial object and locate the index value that it corresponds to. Take that integer value at that index and do the same. Continue doing this until it points back to an object that's already been referenced.
An example: [0, 4, 2, 8, 7, 9, 1, 6, 5, 3]
would be these cycles : [0] [4, 8, 5, 7, 6, 9, 3, 2] [1]
and return this: [0], [1], [2, 4, 8, 5, 7, 6, 9, 3]
or
This array: [2, 4, 8, 1, 5, 3, 9, 0, 7, 6]
would be these cycles : [2, 8, 7, 0] [4, 5, 3, 1] [9, 6]
and return this : [0, 2, 8, 7], [1, 4, 5, 3], [6, 9]
I am so lost, any help would be wonderful. thanks ahead of time!
Don't ask why I took the time to do this.
EDIT: Totally working now
public class Main {
public Main()
{
}
public static void main(String[] args)
{
int array[] = {0, 4, 2, 8, 7, 9, 1, 6, 5, 3};
Main m = new Main();
int[][] cycles = m.getCycles(array);
for (int i = 0; i < cycles.length; i++)
{
System.out.print("[");
for (int j = 0; j < cycles[i].length; j++)
{
System.out.print(cycles[i][j]);
if (j < cycles[i].length - 1)
System.out.print(", ");
}
System.out.println("]");
}
System.out.println("end debug");
}
public int[][] getCycles(int[] array)
{
int[][] cycles = new int[array.length][array.length];
// initialize the cycles to all -1s, cuz they'll never be in the array
for (int i = 0; i < cycles.length; i++)
{
for (int j = 0; j < cycles[i].length; j++)
{
cycles[i][j] = -1;
}
}
int i = 0;
do {
int nextElement = array[i];
int j = 0;
do {
cycles[i][j] = nextElement;
nextElement = array[nextElement];
j++;
} while (!elementInArray(cycles[i], nextElement) && j < array.length);
i++;
} while (!arrayHasCycled(array, cycles) && i < array.length);
cycles = removeNegativeOnes(cycles, i);
for (i = 0; i < cycles.length; i++)
{
pushForward(cycles[i]);
}
return cycles;
}
public boolean elementInArray(int[] array, int element)
{
for (int i = 0; i < array.length; i++)
{
if( array[i] == element)
return true;
}
return false;
}
public int[][] removeNegativeOnes(int[][] cycles, int numCycles)
{
int [][] newCycles = new int[numCycles][];
for (int i = 0; i < numCycles; i++)
{
int realLenOfCycle = indexOf(-1, cycles[i]);
newCycles[i] = new int[realLenOfCycle];
for (int j = 0; j < newCycles[i].length; j++)
{
newCycles[i][j] = cycles[i][j];
}
}
return newCycles;
}
public int indexOf(int element, int[] array)
{
int index = -1;
for (int i = 0; i < array.length; i++)
{
if (array[i] == element)
return i;
}
return index;
}
public boolean arrayHasCycled(int[] array, int[][] cycles)
{
for (int i = 0; i < array.length; i++)
{
boolean cycleHasValue = false;
for (int j = 0; j < cycles.length; j++)
{
for (int k = 0; k < cycles[j].length; k++)
{
if (cycles[j][k] == array[i])
cycleHasValue = true;
}
}
if (!cycleHasValue)
return false;
}
return true;
}
public void pushForward(int [] array)
{
int lastElement = array[array.length - 1];
for (int i = array.length - 1; i > 0; i--)
{
array[i] = array[i - 1];
}
array[0] = lastElement;
}
}
Output:
[0]
[1, 4, 7, 6]
[2]
[3, 8, 5, 9]
From what I understand, you're asked us to create a code which executes the following algorithm:
Create a one-dimensional array of integers, array
For each element in that array, nextElement do the following:
Create a new one-dimensional array, currCycle that will be added to a two-dimensional array, cycles.
Set the first element of that array to nextElement.
nextElement then becomes array[nextElement]
If nextElement is already in currCycle, continue onto the next element of array
Check if all the elements of array are in cycles, and if so, stop executing this algorithm.
Finally, return the cycles as a two-dimensional array with the index that was being used instead of the element at that index, which is what the current array consists of. To accomplish this, just cyclically (in the normal sense) push each element of the array forward one index.
This doesn't follow your examples exactly, but I think you may have malformed your examples, for instance:
An example: [0, 4, 2, 8, 7, 9, 1, 6, 5, 3]
would be these cycles : [0] [4, 8, 5, 7, 6, 9, 3, 2] [1]
and return this: [0], [1], [2, 4, 8, 5, 7, 6, 9, 3]
The first element 0 is 0, so when you get 0, it's already in the current cycle, so go to the next element, the element at index 1, which is 4. Once you're at 4 go to the fourth element, which is 7 not 8!
0 1 2 3 4
[0, 4, 2, 8, 7...