Complexity analysis of algorithm (time complexity and space complexity)

Keywords: Java Algorithm

1. Algorithm complexity:

The time complexity and space complexity of the algorithm are collectively referred to as the complexity of the algorithm.

Time complexity: time complexity refers to the calculation workload required to execute the algorithm;

Space complexity: it is a measure of the amount of storage space temporarily occupied by an algorithm during operation;

The complexity of the algorithm is the number of resources required by the computer when running the algorithm. The most important computer resources are time and space (i.e. register) resources. Therefore, the complexity is divided into time and space complexity.

2. Time complexity:

The time spent by an algorithm is in direct proportion to the execution times of statements in the algorithm. Whichever algorithm has more execution times of statements, it takes more time. The number of statements executed in an algorithm is called statement frequency or time frequency, which is recorded as T(n).

In general, the number of times the basic operation is repeated in the algorithm is a function of the problem scale n, expressed by T(n). If there is an auxiliary function f(n), so that when n approaches infinity, the limit value of T(n) / f(n) is a constant that is not equal to zero, then f(n) is a function of the same order of magnitude of T(n). Note that T(n)=O(f(n)), O(f(n)) is the asymptotic time complexity of the algorithm, which is called time complexity for short.

1. Big O notation:

The notation of using O() to reflect the time complexity of the algorithm is called large o representation.

The complexity of the algorithm can be evaluated from the three perspectives of the best case, the average case and the worst case. Since the average case is mostly the same as the worst case, and the evaluation of the worst case can also avoid worries at home, in general, we should directly estimate the complexity of the worst case when designing the algorithm. The large O representation represents the running time of an algorithm in the worst case.

2. Big O derivation method:

1. Replace all addition constants in the running time with constant 1.

2. In the modified run times function, only the highest order term is retained

3. Remove the constant multiplied by the highest term, and the result is large O-order.

give an example:

Single circulating body:

void Demo(int n){
		for(int j = 0; j < n; j++) {        // The number of cycles is n
            printf("Hello, World!\n");      // The time complexity of the loop body is O(1)
        }
}
//The time complexity is O(n ×  1) , i.e. O(n).

Multi cycle body:

void Demo(int n) {
for(int i = 0; i < n; i++) {            // The number of cycles is n
        for(int j = 0; j < n; j++) {        // The number of cycles is n
            printf("Hello, World!\n");      // The time complexity of the loop body is O(1)
        }
    }
}   
//The time complexity is O(n ×  n  ×  1) , i.e. O(n^2).

Multiple event complexity scenarios:

void Demo(int n) {
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            printf("Hello, World!\n");// The time complexity of the first part is O(n^2)
        }
    }
    for(int j = 0; j < n; j++) {
        printf("Hello, World!\n");// The time complexity of the second part is O(n)
    }
}
//The time complexity is max(O(n^2), O(n)), i.e. O(n^2).

3. Some common large O running times:

  • O(log n), log time, binary search.
  • O(n), linear time, simple search.
  • O(n logn), quick sort - a faster sort algorithm.
  • O(n ²), Select sort - a slower sort algorithm.
  • O(n!), the solution to the traveling salesman problem -- a very slow algorithm.

3. Space complexity:

The spatial complexity of a program refers to the amount of memory required to run a program. Using the spatial complexity of the program, we can estimate in advance the amount of memory required for the operation of the program. When a program is executed, in addition to the storage space and the instructions, constants, variables and input data used to store itself, it also needs some work orders to operate the data Meta and auxiliary space for storing some information required for real-world calculation. The storage space required for program execution includes the following two parts.

(1) Fixed part: the size of this part of space is independent of the number and value of input / output data, mainly including the space occupied by instruction space (i.e. code space) and data space (constants and simple variables). This part belongs to static space.

(2) Variable space: this part of the space mainly includes the dynamically allocated space and the space required by the recursive stack. The size of this part of the space is related to the algorithm. The storage space required by an algorithm is represented by f(n). S(n)=O(f(n)), where n is the scale of the problem and S(n) represents the space complexity.

Generally speaking, as long as the algorithm does not involve the dynamically allocated space and the space required by recursion and stack, the space complexity is usually 0 (1).

4. Specific examples:

1. Time and space complexity of Fibonacci sequence

//Fibonacci sequence in recursive case
long long Fib(int n)
{
      assert(n >= 0);
      return n<2 ? n : Fib(n - 1) + Fib(n-2);
}

The time complexity of recursion is: the number of recursions * the number of basic operations performed in each recursion. Therefore, the time complexity is: O(2^N).

The spatial complexity of recursion is: the depth of recursion * the number of auxiliary spaces required for each recursion. Therefore, the spatial complexity is: O(N).

2. Time complexity and space complexity of dichotomy

In the worst case, the binary search is n/2,n/4,n/8 until 1.
Suppose it is x times, and then we can observe that the denominator is multiplied by 1 / 2 every time, and the numerator remains unchanged, so we can list the following equation:

n(1/2)^x = 1

It is calculated that x=log2N, that is, the time complexity is O(log2N);

Non recursive:

public static int binarySearch(int[] arr,int toFind) {
        int left = 0;
        int right = arr.length-1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (arr[mid] < toFind) {
                left = mid + 1;
            }
            else if (arr[mid] > toFind) {
                right = mid - 1;
            }
            else {
                return mid;
            }
        }
        return -1;
    }

Time complexity: the basic number of cycles is log2N, so the time complexity is O(log2N);

Spatial complexity: since the auxiliary space is constant, the spatial complexity is O(1).

Recursion:

public static int binarySearch(int srcArray[], int start, int end, int key) {
        int mid = (end - start) / 2 + start;
        if (srcArray[mid] == key) {
            return mid;
        }
        if (start >= end) {
            return -1;
        } else if (key > srcArray[mid]) {
            return binarySearch(srcArray, mid + 1, end, key);
        } else if (key < srcArray[mid]) {
            return binarySearch(srcArray, start, mid - 1, key);
        }
        return -1;
    }

The number and depth of recursion are log2N, and the auxiliary space required each time is constant:
Time complexity: O(log2N)
Space complexity: O(log2N)

Posted by maca134 on Mon, 29 Nov 2021 20:45:55 -0800