Big O for 2D for loop - java

I have to write down the Big O notation of an algorithm I had to think up for my homework.
I'm able to tell that the code below is O(n^2). Because for every x I have to go through all of the y's and it becomes slower as the world grows larger.
int[][] world = new world[20][20];
for (int x = 0; x < 20; x++)
{
for (int y = 0; y < 20; y++)
{
..
}
}
But, for another question I have to go through the bottom half of the world, so my y loop gets halved.
int[][] world = new world[20][20];
for (int x = 0; x < 20; x++)
{
for (int y = 10; y < 20; y++)
{
..
}
}
I'm not quite sure what Big O notation is appropriate for the above loop, is it still O(n^2) because it still becomes slower the bigger the world gets? Or is it O(log n) because the y is halved?

it is simply speaking O(n*n/2)=O(n^2) since constants arent considered in big O.

It's O(n^2) as y is still a function of n i.e. O(n^2/2) is still O(n^2).

Both of your algorithms are in fact O(n) (assuming n is the number of bits in the input, which is the common definition). The first one touches each "pixel" in the world array once, so it's easy to see it is O(n). The second one touches half of the pixels, but is still O(n) since O(n/2) = O(n). In both cases, doubling the size of the world array will more or less double the execution time, which is typical of O(n) algorithms.

Related

How can I utilize merge sort approach to reduce running time of my program

I have a function that takes in an int[] array with the expectation that all elements are sorted from largest to smallest.
I want to find how many pairs violate this expectation ( a larger element x in the array is present AFTER a smaller element x + array.length() while not going out of bounds)
For instance,
if array = [7,3,5,4,1] the answer would be 2 because the pairs that violate the order are 3 and 5 and 3 and 4, since 3 is smaller than them and should've been ahead of them.
Here is my current code:
public static int countBad(int[] array){
int counter = 0;
for (int x = 0; x < array.length; x++){
for (int y = x + 1; y <= x + array.length && y < array.length; y++){
if(array[x] < array[x+y]){
counter++;
}
}
}
return counter;
}
Even though my code works, it is extremely inefficient, which is why I wish to reduce the time complexity. I've been told about a merge sort approach to this issue. However, I'm struggling to grasp how to convert my existing method into a merge sort approach.
Can anyone please help explain how to do this?

Matrix multiplication Big O notation

I have a question regarding best case scenario for this piece of code and worst case scenario in Big O notation. From my point of view, it should be O (n^3) for both cases but some people disagree.
public int [][] multiply (int [][] A, int
[][] B, int n) {
int [][] C = new int[n][n]; - 1 ( ignored )
for(int i=0; i<n; i++) { - n
for(int j=0; j<n; j++) { - n
if(A[i][j ]!=0) { - 1 ( ignored )
for (int k=0; k<n; k++) { - n
C[i][k] += A[i][j]*B[j][k]; -
}
}
}
}
return C;
}
It is true that matrix multiplication takes O(n^3) time to run in average and worst cases. For 2 matrices of dimensions m x n and n x p respectively, there is going to be a total of mnp (or n^3 for simplicity) calculations, one for each entry in the resultant matrix. As for the best case, it depends on what your program does when it sees that at least one of the matrices is a zero matrix (all entries in the matrix are 0). If it can spot a zero matrix, then you can short circuit the program. In this case, the running time is going to be O(n^2) (you just scan a couple of n x n matrices at most), which is the best that can be achieved for matrix multiplication. If this optimization is not available, the program will run in O(n^3) in any case. Either way, you can still say that the best case is O(n^3) because of the definition of Big-O notation, but that is not of interest to most people.
The line of code shown above must be corrected.
C[i][k] += A[i][j]*B[j][k];
It should be corrected as follows.
C[i][j] += A[i][k]*B[k][j];

How to calculate the complexity of an algorithm? [duplicate]

This question already has answers here:
How can I find the time complexity of an algorithm?
(10 answers)
Closed 4 years ago.
int sum = 0;
for (int n = N; n > 0; n /= 2)
for(int i = 0; i < n; i++)
sum++;
int sum = 0;
for (int i = 1 i < N; i *= 2)
for (int j = 0; j < i; j++)
sum++;
int sum = 0;
for (int i = 1 i < N; i *= 2)
for (int j = 0; j < N; j++)
sum++;
I have been suffering from this for a lot of time. I am still a second-year student but I still can't calculate the complexity of an algorithm. How can I calculate it? I feel very incompetent because I never seem to get it!
For example, is the complexity of a for loop always N? How to know? Can you recommend any resources I can read? Any videos?
Well your first and second example is same (in terms of time complexity). For them, time complexity is O(N). Why is it. Let us compute. For the first example, your inner loop runs for N times, then N/2 times, then N/4 and goes upto 1. So, the time complexity is O(N+N/2+N/4+..+1) and sum of this GP is (2n-1). So, the time complexity for first case is O(N).
For the second example, your inner loop runs for 1 time, then 2 times, 4 times, and goes upto N. So, the time complexity is O(1+2+4+...+N) and sum of this GP is 2log(N+1)-1 which is equal to N. So, the time complexity for the second case is also O(N).
For the third example, first loop runs for log(N) time and inner loop runs for N time and since each of them is independent, required time complexity is O(NlogN). (All calculations are approximate and all log bases are 2)
Well, to know about time complexity of a for loop, you have to see how many times "i" is assigned a value (can be same or different).
To learn about time complexity, check out hackerearth material and every time you write an algorithm, try to calculate its time complexity. Its the best method to learn it and check out Masters theorem for recurrence relation but know its basic too.
Resource
https://www.geeksforgeeks.org/analysis-of-algorithms-set-4-analysis-of-loops/
Explanation
A general idea, Complexity of a loop means the number of times that will run. So a for loop for(int i=0;i<10;i++) is of Complexity O(n) where n=10. If there are multiple loops (not nested) the complexity of the code will be the highest n. If the loops are nested, like in the 3rd example you have shown above, the limit of both loop, which is N, gets multiplied. Making the complexity O(N square). (This is a general idea and not the precise definition!)
This previous question may be helpful because there are a few different approaches to calculate the complexity of an algorithm, and quite a few good resources.
As for your example, the complexity of a for loop may not always be N.
For example the following code snippet is linear (with a time complexity of N) because it goes from every iteration i = 0 to i = N sequentially,
for (int i = 0; i < N; i++) {
sum++;
}
Whereas this code snippet is logarithmic in its time complexity because it doesn't progress sequentially through every value from 0 to N, but instead is multiplied by 2.
for (int i = 0; i < N; i*2) {
sum++;
}

How to check which points are in a circle?

Okay so say there is a grid, which I have stored as a 2 dimensional array, that is 10 by 10.
int[][] grid = new int[10][10];
The origin of the grid is at the bottom left, like a normal x y plane, and there is a circle of radius 5 in the centre of the grid at (5,5), like so:
I want to go through this array and basically check which points are inside the circle, but I do not want to loop through the entire array. By default, every point on a corner is not going to be in the circle, so I would want to ignore those, and similarly the points that are close to the corner, etc.
Just the points that are in the circle. I have a much bigger grid and looping through unnecessary stuff that I already know isn't in the circle would waste time. Is there a way to do this? Because, given that I already know the radius and centre of the circle, there should be a nice easy way to go through those points which are in the circle and change them from 0 to -1, for example.
Otherwise, I would stand to lose 100 - 25π ≈ 21.46% time.
BETTER CLARITY: I already know that I can bound the circle with a square, and loop through the points in that square and check each points distance from the centre of the circle (x^2 + y^2 < r^2), but this is what I am trying to avoid, due to the constant overhead every time of checking the bits that aren't in the circle, when I know they are not in the circle beforehand.
Ok, after a long discussion, here is the solution. You scan across one axis of a quarter slice, compute the extension to which you need to fill that quarter outwards and then fill all 4 quarters at once.
int n = 1000;
// you will need to think yourself about the odd number or elements
int r = n / 2;
int r2 = r * r;
Putting (0,0) at the centre of the matrix in both cases, the optimized solutions can look like this:
int[][] grid0 = new int[n][n];
for (int i = 0; i < r; i++) {
double m = Math.sqrt(r2 - i * i);
for (int j = 0; j < m; j++) {
grid0[r + i][r + j] = 1;
grid0[r + i][r - j] = 1;
grid0[r - i][r + j] = 1;
grid0[r - i][r - j] = 1;
}
}
As commented elsewhere, the extension of filling the circle is computed in O(n).
Here is the straightforward validation:
int[][] grid1 = new int[n][n];
// you will need to think yourself about the even number
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if ((i - r) * (i - r) + (j - r) * (j - r) < r2) {
grid1[i][j] = 1;
}
}
}
Both produce the same number of filled points.
Time measurements over 10000 executions (with array initialization outside of the time loop):
the optimized one 6.0s
the exhaustive one 15.6s
So, I do admit there is a difference, an astonishing one. Although for a fair comparison, the latter snippet should also be using a quarter slice of the circle.
One can speed up the optimized solution even further using some sort of memory copy routine to fill the values from 0 to the computed point rather than a plain loop, but that is beyond the scope.

How to determine Big O performance by looking at for loops?

I have just begun learning about Big O Notation and honestly I don't think I have the hang of it, and I am not quite sure how to determine the O() performance by just looking at for loops. I have listed a few examples and then some of the answers that I think are correct! Please let me know if they are wrong and any explanations would be greatly appreciated!
for (int i = 0; i <1000; i++) {
count ++;
I believe this would be O(n), because nothing else is going on in the for loop except constant time printing. We iterate 'n' times, or in this case 1000?
for (int i = 0; i < n; i++) {
for(int j = 0; j < n; j++)
count ++;
Would this one have an O(n^2) because the loops are nested and it iterates n twice, n*n?
for (int i = 0; i < n; i++) {
for( int j = i; j < n; j++)
count++;
Is this one another O(n^2) but in the worst case? Or is this O(n log n)?
Big-O notation is supposed to be a guide to help the user understand how the runtime increases with input.
For the first example, the loop runs exactly 1000 times no matter what n is, thus it is O(1000) = O(1) time.
For the second example, the nested loop runs n times for every time the outer loop runs, which runs n times. This is a total of n*n = n^2 operations. Thus the number of operations increases proportional to the square of n, thus we say it is O(n^2).
For the third example, it is still O(n^2). This is because Big-O notation ignores constants in the exact formula of the time complexity. If you calculate the number of times j runs as i increases, you get this pattern.
i: 0 1 2 3 ...
j: n n-1 n-2 n-3 ...
In total, the number of operations is around 1/2 n^2. Since Big-O notation ignores constants this is still O(n^2)

Categories