Time Complexity of the Algorithms - java

I have created two algorithms that calculate the prefix averages with a given array. I wanted to derive the time complexities of both algorithms, but I have been struggling a bit. I watched this YouTube video:
https://www.youtube.com/watch?v=udwxWq9wZgg&safe=active. I did not understand how to count the operations in a for loop and a nested for loop.
At 2:27, I managed to count the operations in the for loop in PrefixAverages2. It was 3n+1. However, I cannot understand from 5:50 onwards.
Thanks in advance.
public double[] PrefixAverages1(double input[])
{
double A[] = new double[input.length];
double s;
for(int i=0; i <= input.length - 1 ;i++)
{
s = input[0];
for(int j=1; j <= i ;j++)
{
s = s + input[j];
}
A[i] = s / (i+1);
}
return A;
}
public double[] PrefixAverages2(double input[])
{
double A[] = new double[input.length];
double s = 0;
for( int i=0; i <= input.length - 1 ; i++)
{
s = s + input[i];
A[i] = s / (i+1);
}
return A;
}

for(int i=0; i <= input.length - 1 ;i++)
for(int j=1; j <= i ;j++)
This is quadratic, for a given i, inner loop goes about i-times, so you have to sum over i, so basically you have something like sum_{i=1}^{i=l} i, which is the sum of the first l integers, so l(l+1)/2, then quadratic.
For the second algorithm you just have one loop so its complexity is linear.

Related

Divisible Sum Pairs

Though it will be weird to see this question I really need to understand some core concepts while I continue my journey of coding. I have a problem which is on Hackerrank it goes like DIVISIBLE SUM PAIRS
I will anyhow give the problem statement here:
Problem Statement
Given an array, where we have to find the number of pairs divisible by the given number k, and there is one more condition to it, which is :
the arr[i] < arr[j] from those pairs.
Example
For example, ar=[1,2,3,4,5,6] and k=5. Our three pairs meeting the criteria are [1,4] [2,3] and [4,6].
Code
Before I publish my code, I would like to tell you that my code has passed all the test cases, and it is accepted to move ahead to the next challenge, but there is a glitch that I'm trying to figure out, which is there in the code.
static int divisibleSumPairs(int n, int k, int[] ar) {
int count = 0;
for(int i=0; i<ar.length; i++){
for(int j=i+1; j<ar.length; j++){
if(((ar[i]+ar[j])%k)==0){
if(i < j)
count++;
}
}
}
return count;
}
Here when I do this if(i < j) count++, it gives me the correct result, but as soon as I do this if(ar[i] < a[j]) count++, it supposedly gives me a wrong answer.
Can anybody help me clear this out, like what is left? Since I know the check arr[i] < arr[j] should give the correct result. I don't want to proceed with the wrong knowledge.
EDITS
Since I have understood what I was doing wrong. And I have one edit in my code that is not starting the inner loop with 1, since it will start off with 1 every time the inner loop finishes, and again runs. I thank everyone who helped me clear this and made my concepts strong enough to deal with the questions like this.
I personally thank Mike 'Pomax' Kamermans, Ricola, and xerx593 for clearing out my doubts and giving me the core concepts of looping through the elements. It will help me in the future, and I won't repeat that thing again. :)
I just checked your link and the condition given in the question statement is
Find and print the number of (i,j) pairs where i < j and ar[i] + ar[j] is divisible by k.
Which is simply the number of unordered pairs of elements for which the sum is divisible by k.
However you wrote
there is one more condition to it, which is : the arr[i] < arr[j] from
those pairs.
I seems like you have misread the question. And it explains why the i<j condition works whereas arr[i] < arr[j] doesn't.
Now that you know that you only need the unordered pairs, no need to iterate j from 1 to ar.length. Since you need j > i, every j between 1 and i (inclusive) is useless. You can simplify your code to:
static int divisibleSumPairs(int n, int k, int[] ar) {
int count = 0;
for(int i=0; i<ar.length-1; i++){
for(int j=i+1; j<ar.length; j++){
if(((ar[i]+ar[j])%k)==0){
count++;
}
}
}
return count;
}
Wen you do i = {0 ... 10} and j = {1 ... 10}, then there are (about) 100 cmobinations (of i and j), (about) 50, where i < j and the rest vice versa. So your assumption is wrong, that:
it is supposedly giving me a wrong answer
...it gives you correctly the wrong answer! ...since when a[i] + a[j] % k == 0, then a[j] + a[i] % k == 0 also!
If you don't include the if(i < j), you count (the occurrence of pairs ..exactly) doubly.
An (implementation) alternative would be:
for (int i = 0; i < ar.length; i++) {
// ensure i < j via initialization ;)
for (int j = i + 1; j < ar.length; j++) {
if (((ar[i]+ar[j]) % k) == 0) {
counter++;
}
}
}
...to initialize the inner loop with i + 1 instead of 1.
EDIT:(after getting the question better)
Your assumption, that a[i] > a[j] is equivalent with i > j OR j < i(but not both), is almost correct: except when a[i] == a[j].
That's my solution in javaScript (Passed all test-cases):
function divisibleSumPairs(n, k, ar) {
let count=0;
for(let i=0; i<n; i++){
for(let j=0; j<n; j++){
if(i<j){
if((ar[i]+ar[j])%k===0) count++;
}
}
}
return count;
}
This solution is using javaScript :
divisibleSumPairs (n, k, ar) => {
let count = 0;
ar = ar.map((value, index, arr) => {
for (let i = index + 1; i <= arr.length; i++) {
if ((value + arr[i]) % k === 0) {
count++;
}
}
});
return count
}
Dart Solution
n = arr.length;
int numberOfDivisiblePairs = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if ((arr[i] + arr[j]) % k == 0) {
numberOfDivisiblePairs++;
}
}
}
return numberOfDivisiblePairs;
A solution in Python 3 (Passed all test-cases):
The itertools.combinations(arr,r) returns the r length subsequences of elements from the input iterable. Combinations are emitted in lexicographic sort order. So, if the input iterable is sorted, the combination tuples will be produced in sorted order.
from itertools import combinations
def divisibleSumPairs(n,ar,k):
pairs = []
for com in combinations(ar,2):
if sum(com) % k == 0:
pairs.append(com)
return len(pairs)
nk = input().split()
n = int(nk[0])
k = int(nk[1])
ar = list(map(int, input().rstrip().split()))
print(divisibleSumPairs(n,ar,k))
If anyone is interested in an O(n) solution, here is my C# solution.
public static int divisibleSumPairs(int n, int k, List<int> ar)
{
Dictionary<int, int> map = new Dictionary<int, int>();
int cnt = 0;
foreach (int elem in ar)
{
int modulo = elem % k;
int complement = modulo == 0 ? 0 : k - modulo;
if (map.ContainsKey(complement))
{
cnt += map[complement];
}
if (map.ContainsKey(modulo))
{
++map[modulo];
}
else
{
map.Add(modulo, 1);
}
}
return cnt;
}
def divisibleSumPairs(n, k, ar):
result = 0
d = {}
for i in range(n):
mod = ar[i] % k
result += d.get(( k - mod ) % k, 0)
d[mod] = d.get(mod, 0) + 1
return result
solution in O(n)

BIG O Analysis of Loops

Can someone provide examples of loops that are PolynomialO O(n^2) , Exponential O(2^n) , and Factorial O(n1). I can't seem to wrap my head around it.
I understand the concepts of O(log n)for (int i=0; i<=10; i=i*2) OR for (int i=0; i<=10; i=i/2)O(n)for (int i=0; i<=10; i++)or (int i=10; i<=0; i--). O(n^2)
`
for (int i=0; i<=10; i++)
{
for (int i=0; i<=10; i++)
{
//DO SOMETHING
}
}
A more obviously O(2^N) example is:
public int count2PowerN(int n) {
if (n <= 1) {
return n;
} else {
return count2PowerN(n - 1) + count2PowerN(n - 1);
}
}
Notes:
O(2^N) is equivalent to any O(c^N) where c is a constant. It is conventional to use e as the nominal constant; i,e O(e^N)
you cannot get super-polynomial complexity with simple nested loops. You need either recursion or a dynamic data structure.
O(n^2):
int count = 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
count++;
}
}
This is pretty simple, for every nested loop you will increase your power. So if you had 3 for loops instead of two, then it would be O(n^3)
O(2^n):
public int fibonacci(int n){
if (n<= 1) return n;
return fibonacci(n- 2) + fibonacci(n- 1);
}
For every iteration of this method, two other "branches" will be created (until n<=1) since it has two recursive calls. So the growth doubles for every iteration.
O(n!):
public int factorialRuntime(int n) {
int count = 0;
for(int i=0; i<n; i++) {
count += factorialRuntime(n-1);
}
return count;
}
This example was pulled from here.

Basic Bubble Sort with ArrayList in Java

I was implementing a comparator, and it wasn't working, so I thought I'd write a basic bubble sort.
int[] numbers = { 5, 8, 14, 1, 5678 };
int tempVar;
for (int i = 0; i < numbers.length; i++)
{
for(int j = 0; j < numbers.length; j++)
{
if(numbers[i] > numbers[j + 1])
{
tempVar = numbers [j + 1];
numbers [j + 1]= numbers [i];
numbers [i] = tempVar;
}
}
}
for (int i = 0; i < numbers.length; i++)
{
System.out.println(numbers[i].toString());
}
Is this tutorial correct at all?
https://blog.udemy.com/bubble-sort-java/
I followed the example and applied it to Last Names in an arraylist, but the results are a bit wack.
String a;
String b;
Person c;
Person d;
for (int i=0; i< list.size(); i++){
for(int j=0; j< list.size()-1; j++){
a = list.get(i).getLastName();
b = list.get(j+1).getLastName();
c = list.get(i);
d = list.get(j+1);
if ( a.compareTo(b) < 0 ) {
Person temp = d;
list.set(j+1, c);
list.set(i, temp);
}
}
}
I'd really like to get a grip on a few methods (like figuring out why my comparator didn't work), but right now I'd just like to get a Bubble Sort to work correctly. Thanks.
In Bubble sort you need to compare only the adjacent elements and swap them(depending up on the condition).
If you are doing ascending order than comparing the adjacent elements and swap if(arr[j]>arr[j+1]).
This moves the largest elements to the end in the first iteration.Thus there are n-1 iterations in outer loop to sort the array where n is the length of the array.
Read this first Bubble sort as the tutorial you mentioned is completely wrong
Corrected code
for (int i = 0; i < numbers.length-1; i++)
{
for(int j = 0; j < numbers.length-i-1; j++)
{
if(numbers[j] > numbers[j + 1])
{
tempVar = numbers [j + 1];
numbers [j + 1]= numbers [j];
numbers [j] = tempVar;
}
}
}
Here is the working link
This is a strange and inefficient implementation, you compare each number which each other. Something like this is much more intuitive (could be improved a little performance-wise, but that is not the point, you will just save a lot of time not accidently making mistakes with the indices and if you really care about performance and not readability use mergesort or quicksort as Java does [Java is using quicksort for primitive types and mergesort for Objects, probably because for primitive types it doesn't matter if the algorithm is stable or not]):
public void bubbleSort(int[] arr) {
boolean change;
do {
change = false;
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
change = true;
}
}
} while (change);
}
Applied to your code (sorts ascending):
boolean change;
do {
change = false;
for (int i = 0; i < list.size() - 1; i++) {
c = list.get(i);
d = list.get(i + 1);
a = c.getLastName();
b = d.getLastName();
// add special comparison for null values if a or b can be null ("" is ok)
// toLowerCase() is to compare case-insensitive ('a' != 'A')
if (a.toLowerCase().compareTo(b.toLowerCase()) > 0) {
list.set(i, d);
list.set(i + 1, c);
change = true;
}
}
} while (change);
Sidenote: s.toUpperCase().compareTo(s.toLowerCase()) == 0 would be true if s only contains symbols.
Thanks to everyone for pointing me in the right direction.
One problem was I forgot to .trim() so compareTo wasn't working and neither was comparing with charAt(0).
Also, I found a better implementation of loops for Bubble-Sort.
This is what now works:
String a;
String b;
Person c;
Person d;
for (int i= 0; i< list.size() ; i++){
for(int j=0; j< list.size() - i-1; j++){
a = list.get(j).getLastName().toUpperCase().trim();
b = list.get(j+1).getLastName().toUpperCase().trim();
c = list.get(j);
d = list.get(j+1);
if ( a.compareTo(b) > 0) {
Person temp = d;
list.set(j+1, c);
list.set(j, temp);
}
}
If you write,
for(int j = 0; j < numbers.length; j++)
Then, you will get ArrayIndexOutOfBoundsException for the following line,
tempVar = numbers [j + 1];
Because, the array numbers has length 5 with last index 4 (as index starts from 0). So, when j = 4, the loop breaking condition j < numbers.length or 4 < 5 is true, but you will get exception accessing numbers [4 + 1] index.
So try
for(int j = 0; j < numbers.length -1; j++)
or
for(int j = i; j < numbers.length -1; j++) // more efficient
Now for the second snippet of your code, can you tell me what exactly the problem you get?
From a wild guess, your a.compareTo(b) < 0 is not working like what you want.
Note that compareTo returns a value less than 0 if string a is lexicographically less than the string b.
I'm confused what exactly you want, hence produces the following code which may help you to overcome your problem:
import java.util.ArrayList;
public class Sort{
private static ArrayList<String> list = new ArrayList<String>();
public static ArrayList<String> sortByName(String [] input) {
String temp;
for (int i=0; i< input.length; i++){
for(int j= i; j< input.length-1; j++){
char first = input[i].charAt(0);
char sec = input[j +1].charAt(0);
if (first < sec) {
temp = input[j +1];
input[j +1] = input[i];
input[i] = temp;
}
}
list.add(input[i]);
}
return list;
}
public static void main(String[] args) {
String string[] = {"Ezen", "Allen" , "Wilker", "Kruden", "Crocket"};
bubbleSortByName(string);
}
}
Output is a list containing:
list = [Wilker, Kruden, Ezen, Crocket, Allen]
Bubble Sort Swap Printer in JAVA:
static void countSwaps(int[] a) {
int swaps = 0;
for(int i=0; i<a.length-1; i++){
for(int j=0; j<a.length-i-1; j++){
if (a[j] > a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
swaps++;
}
}
}
System.out.println("Array is sorted in " + swaps +" swaps.");
}
There is a small problem with the sort program you used originally.
int j=0
should be
int j=i
Also you didn't exactly replace it for string sorting.
a.compareTo(b) < 0
should be
a.compareTo(b) > 0
Check this:
import java.util.*;
public class HelloWorld{
public static void main(String[] args){
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("xyz"));
list.add(new Person("abc"));
list.add(new Person("pqr"));
list.add(new Person("lmn"));
String a;
String b;
Person c;
Person d;
for (int i=0; i< list.size(); i++){
for(int j=i; j< list.size()-1; j++){
a = list.get(i).getLastName();
b = list.get(j+1).getLastName();
c = list.get(i);
d = list.get(j+1);
if ( a.compareTo(b) > 0 ) {
Person temp = d;
list.set(j+1, c);
list.set(i, temp);
}
}
}
for(Person person: list){
System.out.println(person.lastName);
}
}
}
class Person{
String lastName;
Person(String str){
lastName = str;
}
public String getLastName(){
return lastName;
}
}

Raising a matrix to the power method JAVA

I am having a really hard time creating a method to raise a matrix to the power. I tried using this
public static int powerMethod(int matrix, int power) {
int temp = matrix ;
for (int i = power; i == 1; i--)
temp = temp * matrix ;
return temp ;
but the return is WAYYY off. Only the first (1,1) matrix element is on point.
I tried using that method in a main like so
// Multiplying matrices
for (i = 0; i < row; i++)
{
for (j = 0; j < column; j++)
{
for (l = 0; l < row; l++)
{
sum += matrix[i][l] * matrix[l][j] ;
}
matrix[i][j] = sum ;
sum = 0 ;
}
}
// Solving Power of matrix
for (i = 0; i < row; i++) {
for (j = 0; j < column; j++)
matrixFinal[power][i][j] = Tools.powerMethod(matrix[i][j], power) ;
}
Where "power", "row", and "column" is an int that the user enters.
Any ideas how I can do this??
Thanks!!!
You have a lot of issues here.
First, your matrix squaring algorithm has a (common) error. You have:
for (i = 0; i < row; i++) {
for (j = 0; j < column; j++) {
for (l = 0; l < row; l++) {
sum += matrix[i][l] * matrix[l][j] ;
}
matrix[i][j] = sum ;
sum = 0 ;
}
}
However, you need to store the result in a temporary second matrix, because when you do matrix[i][j] = sum, it replaces the value at that position with the output, then later results end up being incorrect. Also I suggest initializing sum to 0 first, since it appears you declare it outside of this loop, and initializing it first protects you against any arbitrary value sum may have before going into the loop. Furthermore, it is not immediately clear what you mean by row and column -- make sure you are iterating over the entire matrix. E.g.:
int temp[][] = new int[matrix.length];
for (i = 0; i < matrix.length; i++) {
temp[i] = new int[matrix[i].length];
for (j = 0; j < matrix[i].length; j++) {
sum = 0 ;
for (l = 0; l < matrix.length; l++) {
sum += matrix[i][l] * matrix[l][j] ;
}
temp[i][j] = sum ;
}
}
// the result is now in 'temp', you could do this if you wanted:
matrix = temp;
Note that matrix.length and matrix[i].length are fairly interchangeable above if the matrix is square (which it must be, in order to be multiplied by itself).
Secondly, your multiplication squares a matrix. This means if you repeatedly apply it, you keep squaring the matrix every time, which means you will only be able to compute powers that are themselves powers of two.
Your third issue is your final bit doesn't make much sense:
for (i = 0; i < row; i++) {
for (j = 0; j < column; j++)
matrixFinal[power][i][j] = Tools.powerMethod(matrix[i][j], power) ;
}
It's not immediately clear what you are trying to do here. The final part seems to be trying to raise individual elements to a certain power. But this is not the same as raising a matrix to a power.
What you need to do is define a proper matrix multiplication method that can multiply two arbitrary matrices, e.g.:
int[][] multiplyMatrices (int[][] a, int[][] b) {
// compute and return a x b, similar to your existing multiplication
// algorithm, and of course taking into account the comments about
// the 'temp' output matrix above
}
Then computing a power becomes straightforward:
int[][] powerMatrix (int[][] a, int p) {
int[][] result = a;
for (int n = 1; n < p; ++ n)
result = multiplyMatrices(result, a);
return result;
}
Why not just use Math.pow?
import java.lang.Math;
Then you just have to do
matrixFinal[power][i][j] = (int) Math.pow(matrix[i][j],power); //might have to cast this to an int

Optimal solution for the maximum single sell profit algorithm

The input array is:
A[0] = 23171
A[1] = 21015
A[2] = 21123
A[3] = 21366
A[4] = 21013
A[5] = 21367
Mission is to find maximum profit. E.g A[3] - A[2] = 243
and my code is:
class Solution {
int profit = 0;
public int solution(int[] A) {
for (int i = 0;i < A.length; i++){
for (int j = i + 1; j < A.length; j++){
if(A[j] - A[i] > profit)
profit = A[j] - A[i];
}
}
return profit;
}
}
The result is suppose to be 365 but it blows up on larger inputs.
This code has a time complexity of O(N2) but is possible to do with O(N). I can't really see how to avoid nesting here... Any pointers in the right direction appreciated.
You only need to get max value and min value from your array and substract them both, so in a O(N) iteration, get the min and the max values.
class Solution {
public int solution(int[] A) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0;i < A.length; i++){
if(A[i] > max) max = A[i];
if(A[i] < min) min = A[i];
}
return max - min;
}
}
I think that most of you got it wrong. The problem in the post is the maximum single sell profit problem which is a typical interview question.
The most optimal solution:
public int dynamicProgrammingSingleSellProfit(int[] arr) {
if(arr.length == 0) {
return 0;
}
int profit = 0;
int cheapest = arr[0];
for (int i = 0; i < arr.length; i++) {
cheapest = Math.min(cheapest, arr[i]);
profit = Math.max(profit, arr[i] - cheapest);
}
return profit;
}
It has O(n) time and O(1) space complexity.
If you examine the original question the op is looking for profit and since we can't travel in time (yet) you can't just compare the minimum and the maximum in the array.

Categories

Resources