Skip to content

Introduction To Arrays

Space Complexity

  • Space complexity is the max space(worst case) that is utilised at any point in time during running the algorithm.
  • We also determine Space Complexity using Big O.

Consider the following example:

func(int N) { // 4 bytes
    int x; // 4 bytes
    int y; // 4 bytes
    long z; // 8 bytes
}
  • We only consider the space utilised by our program and not the Input Space since it is not in our control, hence we'll ignore space taken by "int N".
  • The above code takes total 16B of memory.
  • Hence, we say the Space Complexity of the above code is O(1) (1 resembles constant).

Question

Find the Space Complexity [Big(O)] of the below program.

func(int N) { // 4 bytes
    int arr[10]; // 40 Bytes
    int x; // 4 bytes
    int y; // 4 bytes
    long z; // 8 bytes
    int[] arr = new int[N]; // 4 * N bytes
}
Choices

  • N
  • 4N + 60
  • Constant
  • N^2

Question

Find the Space Complexity [Big(O)] of the below program.

func(int N) { // 4 bytes
    int x = N; // 4 bytes
    int y = x * x; // 4 bytes
    long z = x + y; // 8 bytes
    int[] arr = new int[N]; // 4 * N bytes
    long[][] l = new long[N][N]; // 8 * N * N bytes
}

Choices

  • N
  • 4N + 60
  • Constant
  • N^2

Question on Space Complexity

Find the Space Complexity [Big(O)] of the below program.

int maxArr(int arr[], int N) {
    int ans = arr[0];
    for(i from 1 to N-1) {
        ans = max(ans, arr[i]);
    }
    return ans;
}

Space complexity: O(1)

  • Don't consider the space acquired by the input size. Space complexity is the order of extra space used by the algorithm.
  • arr[] is already given to us, we didn't create it, hence it'll not be counted in the Space Complexity.
  • int N will also not be counted in space but since it is contant hence doesn't matter.
  • Additional space is also called computational or auxiliary space.
  • The above code finds the max element of the Array.

Introduction To Arrays

Definition

Array is the collection of same types of data. The datatype can be of any type i.e, int, float, char, etc. Below is the declaration of the array:

int arr[n];

Here, ‘int’ is the datatype, ‘arr’ is the name of the array and ‘n’ is the size of an array.
We can access all the elements of the array as arr[0], arr[1] ….. arr[n-1].

Note: Array indexing starts with 0.

Why indexing starts at 0 ?

An array arr[i] is interpreted as *(arr+i). Here, arr denotes the address of the first array element or the 0 index element. So *(arr+i) means the element at i distance from the first element of the array.

Question

What will be the indices of the first and last elements of an array of size N?

Choose the correct answer

Choices

  • 1,N
  • 0,N-1
  • 1,N-1
  • 0,N

Introduction to Arrays Continued

The elements of arrays can be printed by simply traversing all the elements. Below is the pseudocode to print all elements of array.

void print_array(int arr[],int n){
    for(int i=0;i<n;i++){
        print(arr[i]);
    }
}

Question

What is the time complexity of accessing element at the ith index in an array of size N?

Choices

  • O(N)
  • O(1)
  • O(N*N)
  • O(log(N)).

Question

int arr[5] = {5,-4,8,9,10}
Print sum of 1st and 5th element
Choose the correct answer

Choices

  • print(arr[0]+arr[5])
  • print(arr[0]+arr[4])
  • print(arr[1]+arr[5])
  • print(arr[1]+arr[4])

Question 1 Reverse the array

Given an array 'arr' of size 'N'. Reverse the entire array.

TestCase:

Input:

N = 5
arr = {1,2,3,4,5}

Output:

arr = {5,4,3,2,1}

Warning

Please take some time to think about the solution approach on your own before reading further.....

Approach

The simplest approach to solve the problem is to keep two pointers at the end, traverse the array till middle element and swap first element with last element, second with second last, third with third last and so on.

What should be the stopping condition?

Say N = 6

i j swap
0 5 A[0] & A[5]
1 4 A[1] & A[4]
2 3 A[2] & A[3]
3 2 STOP

Say N = 5

i j swap
0 4 A[0] & A[4]
1 3 A[1] & A[3]
2 2 STOP

We can stop as soon as i>=j

Pseudocode

Function reverse(int arr[], int N) {
  int i = 0, j = N - 1;
  while (i < j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
    i++;
    j--;
  }
}

Complexity:

Time Complexity - O(N).
Space Complexity - O(1).

Question 2 Reverse in a range

Given an array 'arr' of size 'N' and integers 'l' and 'r'. Reverse the array from 'l' to 'r'.

TestCase:

Input:

N = 5
arr = {1,2,3,4,5}
[0 based index]
l = 1 
r = 3 

Output:

arr = {1,4,3,2,5}

Pseudocode

Function reverse(int arr[], int N, int l, int r) {
    while (l < r) {
        int temp = arr[l];
        arr[l] = arr[r];
        arr[r] = temp;
        l++;
        r--;
    }
}

Complexity:

Time Complexity - O(N).
Space Complexity - O(1).

Question 3 Rotate K times

Given an array 'arr' of size 'N'. Rotate the array from right to left 'K' times. (i.e, if K = 1, last element will come at first position,...)

TestCase:

Input:

N = 5
arr = {1,2,3,4,5}
k = 2

Output:

arr = {4,5,1,2,3}

Explanation:

Initially the array is:

| 1 | 2 | 3 | 4 | 5 |

After 1st rotation:

| 5 | 1 | 2 | 3 | 4 |

After 2nd rotation:

| 4 | 5 | 1 | 2 | 3 |

Warning

Please take some time to think about the solution approach on your own before reading further.....

BruteForce Approach

Simple approach is to rotate the array one element at a time.

Pseudocode

Function rotateK(int arr[], int N, int K) {
    for (int i = 0; i < K; i++) {
        int temp = arr[N - 1];
        for (int j = N - 1; j >= 1; j--) {
            arr[j] = arr[j - 1];
        }
        arr[0] = temp;
    }
}

Complexity:

Time Complexity - O(N*K).
Space Complexity - O(1).

Optimized Approach

Success

Please take some time to think about the optimised solution approach on your own before reading further.....

Optimized Appraoch Observations

  • After K rotations, last K elements become 1st K elements and rest elements will go at back.

    For example - Suppose we have an array arr as shown below and k = 3.
    1 2 3 4 5 6 7
    After 1st rotation, k=1:
    7 1 2 3 4 5 6
    After 2nd rotation, k=2:
    6 7 1 2 3 4 5
    After 3rd rotation, k=3:
    5 6 7 1 2 3 4

So, we have observed that last 3(K=3) elements i.e, 5 6 7 comes in front and rest elements appear at the end.

Therefore, we will first reverse the entire array, then reverse first K elements individually and then next N-K elements individually.

1 2 3 4 5 6 7    //Given Array, K=3

7 6 5 4 3 2 1    //Reversed Entire Array

5 6 7 4 3 2 1    //Reversed first K elements

5 6 7 1 2 3 4    //Reversed last N-K elements    

Pseudocode

Function countgreater(int arr[], int N, int k) {
    reverse(arr, N, 0, N - 1);
    reverse(arr, N, 0, K - 1);
    reverse(arr, N, K, N - 1);
}

Edge Case

K might be very large but if we observe carefully then after N rotations the array comes to its initial state.

Hence, K rotation is equivalent to K%N rotations.

Suppose we have an array:
1 2 3 4
After 1st rotation, the array becomes:
2 3 4 1
After 2nd rotation, the array becomes:
3 4 1 2
After 3rd rotation, the array becomes:
4 1 2 3
Afer 4th rotation, the array becomes:
1 2 3 4

Hence, we have concluded that after N rotations, the array become same as before 1st rotation.

Final Pseudocode

Function countgreater(int arr[], int N, int K) {
    K = k % N;
    reverse(arr, N, 0, N - 1);
    reverse(arr, N, 0, K - 1);
    reverse(arr, N, K, N - 1);
}

Complexity:

Time Complexity - O(N).
Space Complexity - O(1).

Dynamic Arrays

Question:

What is the drawback of normal arrays?

Issue:

The size has to be declared before hand.

Dynamic Arrays

  • A dynamic array is an array with a big improvement: automatic resizing.
  • It expands as you add more elements. So you don't need to determine the size ahead of time.

Strengths:

Fast lookups: Just like arrays, retrieving the element at a given index takes O(1) time. Variable size: You can add as many items as you want, and the dynamic array will expand to hold them.

Weaknesses:

Slow worst-case appends:

  • Usually, adding a new element at the end of the dynamic array takes O(1) time.
  • But if the dynamic array doesn't have any room for the new item, it'll need to expand, which takes O(n) time.
    • It is because we have to take a new array of bigger size and copy all the elements to a new array and then add a new element.
    • So, Time Complexity to add a new element to Dynamic array is O(1) amortised.
  • Amortised means when most operations take O(1) but some operations take O(N).

Dynamic Arrays in Different Languages

Java

ArrayList<String> al = new ArrayList<>(); //Arraylist is created
al.add("50"); //50 is inserted at the end
al.clear(); // al={} 
for (int i = 0; i < al.size(); i++) {
    System.out.print(al.get(i) + " ");
}                                        //iterating the Arraylist

C++

vector<int> a; //vector is created
a.push_back(60); 
//a = {10, 20, 30, 40, 50, 60} after insertion at end

a.clear(); // a={} 
for(int i=0; i<a.size(); i++) {
    cout<<a[i];
}                             //iterating the vector

Python

thislist = [] //created list
thislist.append("orange") //added orange at end
thislist.clear()    //cleared the list
for i in range(len(thislist)):
  print(thislist[i])  //iterating on the list