Basic Time Complexity
Considering this is the first chapter, I will not provide an exhaustive explanation of time and space complexity. A detailed Practical Guide to Algorithm Time and Space Complexity Analysis is scheduled after you have learned the core frameworks of several common algorithms, by which time your knowledge reserve will easily accommodate various scenarios of complexity analysis.
Since the later content of this chapter will guide you through implementing common sorting algorithms and data structures, I will analyze their time complexities, so it is necessary to introduce the concept of time/space complexity and the simplified methods for analysis here to prevent confusion for beginners.
For beginners, you only need to remember the following points:
- Time and space complexities are represented using Big O notation (such as , etc.). These are estimates and do not require precise calculations. Constant terms and low-growth terms can be ignored, keeping only the highest growth term.
For example, is equivalent to , and is equivalent to .
When analyzing algorithm complexity, we consider the worst-case complexity. This will be demonstrated in the examples below.
Time complexity measures the execution efficiency of an algorithm, and space complexity measures its memory consumption. Both are better when smaller.
For example, an algorithm with time complexity is more efficient than one with , and an algorithm with space complexity uses less memory than one with .
Of course, it is generally necessary to specify what represents, such as the length of the input array.
- How to estimate? For now, you can simply understand: time complexity is mostly determined by the maximum nesting level of for loops; space complexity is determined by how much space the algorithm allocates to store data.
Note
The analysis methods above contain some inaccuracies:
Estimating time complexity by the nesting level of for loops is a simplified method and not completely accurate.
Most of the time, we analyze the worst-case complexity, but for complexity measurement of data structure APIs, we analyze the average complexity.
A complete method of complexity analysis will be specifically introduced in the Practical Guide to Algorithm Time and Space Complexity Analysis. The estimation methods above are sufficient for learning the content of this chapter.
Let's illustrate with a few examples for clarity.
Case Studies of Time/Space Complexity
Example One, Time Complexity , Space Complexity :
// input an integer array, return the sum of all elements
int getSum(int[] nums) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
return sum;
}
算法包含一个 for 循环遍历 nums
数组,所以时间复杂度是 ,其中 n
代表 nums
数组的长度。
我们的算法只使用了一个 sum
变量,这个 nums
是题目给的输入,不算在我们算法的空间复杂度里面,所以空间复杂度是 。
示例二,时间复杂度 ,空间复杂度 :
// Calculate the sum when n is a multiple of 10, otherwise return -1
int sum(int n) {
if (n % 10 != 0) {
return -1;
}
int sum = 0;
for (int i = 0; i <= n; i++) {
sum += i;
}
return sum;
}
其实只有当 n
是 10 的倍数时,算法才会执行 for 循环,时间复杂度是 。其他情况下算法会直接返回,时间复杂度是 。
但是算法复杂度只考察最坏情况,所以这个算法的时间复杂度是 ,空间复杂度是 。
示例三,时间复杂度 ,空间复杂度 :
// Does the array contain two numbers whose sum is target?
boolean hasTargetSum(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
return true;
}
}
}
return false;
}
The algorithm is nested with two for loops, so the time complexity is , where represents the length of the nums
array.
Our algorithm only uses two variables, i
and j
, which is a constant level of space consumption, so the space complexity is .
You might say that the inner for loop does not traverse the entire array and may return early, so the actual execution times of the algorithm should be less than . Is the time complexity still ?
Yes, it is still . For different inputs, the actual execution times of the algorithm might indeed be less than , but we do not need to focus on these details; estimating the worst-case time complexity is sufficient.
Each for loop has a time complexity of in the worst case, and when combined, the total time complexity is .
Example Four, Time Complexity , Space Complexity :
void exampleFn(int n) {
int[] nums = new int[n];
}
This function creates an array of size n
, so the space complexity is .
In Java, the operation new int[n]
allocates array space and initializes all elements to 0. The memory allocation operation itself can be considered in time complexity, but initializing all elements is equivalent to a hidden for loop, with a time complexity of . Thus, the total time complexity is .
Time complexity is not only reflected in visible for loops; each line of code may have hidden time complexities. Therefore, understanding the implementation principles of common data structures provided by programming languages is the basis for accurately analyzing time complexity.
Example Five, Time Complexity , Space Complexity :
// input an integer array, return a new array where each element is
// the square of the corresponding element in the original array
int[] squareArray(int[] nums) {
int[] res = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
res[i] = nums[i] * nums[i];
}
return res;
}
Initializing the res
array in the algorithm requires a time complexity of , which includes a for loop, also having a time complexity of . Therefore, the total time complexity remains , where n
represents the length of the nums
array.
We declare a new array res
with the same length as the nums
array, so the space complexity is .
For beginners, understanding these basic analyses of time and space complexity is sufficient for now. Let's continue learning.