Pages

Big O Notation



Big O notation is the language we use for talking about how long an algorithm takes to run.

  • We can measure in terms of efficiency what is good or bad code.

  • We can measure what is code that can scale that as the number of Arrays or inputs increases.

What is a good code?

1- Readable

2- Scalable (Big O)

  • Speed (Time complexity).
    • How fast is our function?
    • how much time that the function takes to run?
    • how many operation it will cost?

You want things to go faster, you might need to sacrifice more memory

  • Memory (Space Complexity)
    • Computer has a limited memory

You want to use less memory, so you might need to increase the speed


Time complexity

Linear Time

BigO: O(n)

Performance: Fair. In the Big-O complexity chart it is considered Yellow color.

  • Description: BigO(n)

Explanation: It takes linear time to find a nemo.

  • The O(n) where BigO depends on n (number of items in the array).
                5               x
                4           x
Number of       3       x
Operations      2 
                1   2   3   4   5
                    Elements

Implementation:

    public void Linear(string[] arr){
        for(var i = 0; i < arr.Length; i++){
            if(arr[i] == "NEMO"){
                System.Console.WriteLine("Found NEMO!");
            }
        }
    }
Examples:
 var arr = ["nemo"];

Result: O(1)

 var arr = new string()[1000];

Result: O(1000)

Constant Time

BigO: O(1)

No matter how many times the array increase, we are always just grabbing the first item in the array. It's a flat line in terms of scalability.

Performance: Excellent. In the Big-O complexity chart it is considered Green color.

With 1 operation
                4               
                3           
Number of       2       
Operations      1   x   x   x
                0   1   2   3   4
                    Elements
function compressFirstBos(boxes){
    console.log(boxes[0]); //0(1)
}
With 2 operations
                4               
                3           
Number of       2   x   x   x   
Operations      1   
                0   1   2   3   4
                    Elements
function compressFirstBos(boxes){
    console.log(boxes[0]);  //0(1)
    console.log(boxes[1]);  //0(1)
}

Quadratic Time

BigO: O(n^2)

Every time we have a new element, the **number of operations increase dramatically **

Performance: Horrible. In the Big-O complexity chart it is considered Red color.

                9          x
                8         
                7          
                6         
                5        
                4              
                3       x    
Number of       2      
Operations      1   
                0   1   2   3   4 
                    Elements

An example is we want to log al pair of array

const boxes ['a', 'b', 'c', 'd', 'e']

function logAllPairOfArray(array){
   for(let i = 0; i < array.length; i++){
      for(let j = 0; j < array.length; j++){
        console.log(array[i], array[j]);
      }
   }
}
logAllPairOfArray(boxes);

Result:

a a
a b
a c
a d
a e
b a
...
e e

The Big O is O(n * n) or simply O(n^2)

Factorial Time

BigO: O(n!)

The most expensive one, we have a nested loop for every element that you are interacting.

Performance: Horrible. In the Big-O complexity chart it is considered Red color.


Space Complexity

Follow the code:

function myFunction(n){
   for(let i = 0; i < n.length; i++){
      console.log('hi!')
   }
}

myFunction([1,2,3,4,5]);

What is the space complexity of it?

Space complexity means additional space, so we do not really care how big the input, but when we call the function we reserve the space in memory. The Big in this case is: Big O = O(1)

Another example

function myFunction(n){
   let myArray = []; //Allocate space in Memory
   for(let i = 0; i < n.length; i++){. // i = 0 allocate space in memory
      myArray[i] = "hi"
   }
   return myArray;
}

myFunction([1,2,3,4,5]);

In this case we are adding one element per operation to the array. What is the complexity here? We create variables (i = 0)

We create data structure myArray

The big O for this case is: Big O = O(n)

Rules

Rule 1 - Always worst Case

What is the problem with this function?

const arr = ['dory', 'bruce', 'marlin', 'nemo', 'gill', bloat', 'nigel']

 function findNemo(array){
   for(let i = o; i < array.length; i++){
     if(array[i] === 'nemo'){
       console.log('Found NEMO!');
     }
   }
}
findNemo(arr);

Considering that NEMO is not at the beginning of the array, the first rule says that we already have to consider the worst so it means NEMO can be at the last index of the array. But the wrong on this function is that even tough the 'nemo' was found, the loop still proceed for the next until the very last index of the array.

An away to improve this code would be implement a break in the loop in order to stop the loop when nemo is found!

Rule 2 - Remove Constants

Considering the Big O of O(1 + n/2 + 100), we simple do not care about the numbers, because constants we cannot scale, we already know the number. However considering 'n' as a number that can contains an array of 1 element or 100000 elements and it is important and it means that this can be scaled, hence this is going to be measure as 'linear time complexity'

The result will be: O(n)

Other examples:

O(a + 50) the result will be O(a)

function compressBoxTwice(boxes){
   boxes.forEach(function(boxes) {
     console.log(boxes)
   }

   boxes.forEach(function(boxes) {
     console.log(boxes)
   }
}

this code is: O(2n) the result will be O(n)

Rule 3 - Different terms for inputs

When we have 2 or more parameters, such this example:

function compressBoxTwice(boxes, boxes2){
   boxes.forEach(function(boxes) {
     console.log(boxes)
   }

   boxes2.forEach(function(boxes) {
     console.log(boxes)
   }
}

The Big O of this code is: Big O(a + b). The reason that we should not use Big O(n) even tough there are 2 foreach, means that for this scenario, one input can have more items or less items comparing with the second input.

function compressBoxTwice(boxes, boxes2){
   boxes.forEach(function(boxes) {
      boxes2.forEach(function(boxes) {
     console.log(boxes)
     }
   }  
}

The Big O of this code is: Big O(a * b). When we have nested loop in multiple instead of sum the Big O.

Rule 4 - Drop Non-dominant terms

Considering the example bellow:

function printAllNumbersThenAllPairSums(numbers){
  numbers.forEach(function(number){
    console.log(number);
  });

  numbers.forEach(function(firstNumber){
    numbers.forEach(function(secondNumber){
    console.log(firstNumber + secondNumber);
    });
  });
}

The big O is 0(n + n^2). For this rule we drop the non dominant term, it means that we only keep the one that is more costs in terms of performance, in that case we care only in the most important term. So the result will be O(n^2) and we drop n because this is not important.

Other examples:

O(x^2+3x+1000+x/2) we simply by dropping non-dominant term when:

Considering x = 5
Then: x^2 (x * x) = 25
and 3x = 15
and 100 (constant)
and x/2 = 2.5

In this case 100 is the dominant term because represents the bigger number, however considering that we should drop the constant because we always have to be worried about scale and things intend to be large, so the dominant will be x^2 that is the second bigger number. Another example now comparing x = 500

Considering x = 500
Then: x^2 (x * x) = 250000
and 3x = 1500
and 100 (constant)
and x/2 = 250

In this case you can see that x^2 or x * x is equals 250000 and intend to be larger because it scales depending on the number of elements of the array.


Conclusion

To measure the space complexity vs time complexity we have to consider that sometimes we have limitation in terms of memory. Also we can measure the time vs space complexity base on the questions such as:

What can cause time in a function?
1. Operations
2. Looping
3. Comparison
4. External function calls


What causes the space complexity?
1. Variables
2. Data structures (Arrays, stacks, queues, hash tables)
3. Function call
4. Allocations

That is it for this article, I hope that you have enjoyed and please give me any feedback or thoughts about it. See you in the next article.


------------------------------------------

References: https://www.bigocheatsheet.com/


Alexandre Yembo

No comments:

Post a Comment