Introduction
This pattern describes an interesting approach to deal with problems involving arrays containing numbers in a given range. For example, take the following problem:
You are given an unsorted array containing n numbers taken from the range 1 to n. The array can have duplicates, which means that some numbers will be missing. Find all the missing numbers.
To efficiently solve this problem, we can use the fact that the input array contains numbers in the range of 1
to n
.
For example, to efficiently sort the array, we can try placing each number at its correct place, i.e., placing 1 at index '0'
, placing 2
at index ‘1’, and so on.
Once we are done with the sorting, we can iterate the array to find all indices missing the correct numbers. These will be our required numbers.
Let’s jump on to our first problem to understand the Cyclic Sort pattern in action.
*Cyclic Sort (easy)
Design Gurus Educative.io
Problem Statement
We are given an array containing ‘n’ objects. Each object, when created, was assigned a unique number from 1 to ‘n’ based on their creation sequence. This means that the object with sequence number ‘3’ was created just before the object with sequence number ‘4’.
Write a function to sort the objects in-place on their creation sequence number in O(n) and without any extra space. For simplicity, let’s assume we are passed an integer array containing only the sequence numbers, though each number is actually an object.
Example 1:
1 | Input: [3, 1, 5, 4, 2] |
Example 2:
1 | Input: [2, 6, 4, 3, 1, 5] |
Example 3:
1 | Input: [1, 5, 6, 4, 3, 2] |
Constraints:
n == nums.length
- 1 <= n <= 10^4
- 0 <= nums[i] <= n
Solution
As we know, the input array contains numbers from the range 1
to n
. We can use this fact to devise an efficient way to sort the numbers. Since all numbers are unique, we can try placing each number at its correct place, i.e., placing 1
at index ‘0’
, placing 2
at index ‘1’
, and so on.
To place a number (or an object in general) at its correct index, we first need to find that number. If we first find a number and then place it at its correct place, it will take us O(N^2), which is not acceptable as mentioned in the problem statement.
Instead, what if we iterate the array one number at a time, and if the current number we are iterating is not at the correct index, we swap it with the number at its correct index. This way, we will go through all numbers and place them at their correct indices, hence, sorting the whole array.
Let’s see this visually with the above-mentioned Example-2:
Code
Here is what our algorithm will look like:
这道题使用的算法有几个约束条件,一定要是连续的自然数,而且没有重复,虽然这里是从1开始的自然数,但是不从一开始也可以,只要加上一个偏置就好了 。
1 | class Solution: |
Time complexity
The time complexity of the above algorithm is O(n). Although we are not incrementing the index i
when swapping the numbers, this will result in more than ‘n’ iterations of the loop, but in the worst-case scenario, the while
loop will swap a total of ‘n-1’ numbers and once a number is at its correct index, we will move on to the next number by incrementing i
. So overall, our algorithm will take O(n) + O(n-1) which is asymptotically equivalent to O(n)。
Space complexity
The algorithm runs in constant space O(1).
*Find the Missing Number (easy)
268. Missing Number Design Gurus Educative.io
Problem Statement
We are given an array containing ‘n’ distinct numbers taken from the range 0 to ‘n’. Since the array has only ‘n’ numbers out of the total ‘n+1’ numbers, find the missing number.
Example 1:
1 | Input: |
Example 2:
1 | Input: |
Constraints:
n == nums.length
- 1 <= n <= 10^4
0 <= nums[i] <= n
- All the numbers of
nums
are unique.
Solution
This problem follows the Cyclic Sort pattern. Since the input array contains unique numbers from the range 0 to ‘n’, we can use a similar strategy as discussed in Cyclic Sort to place the numbers on their correct index. Once we have every number in its correct place, we can iterate the array to find the index which does not have the correct number, and that index will be our missing number.
However, there are two differences with Cyclic Sort:
- In this problem, the numbers are ranged from ‘0’ to ‘n’, compared to ‘1’ to ‘n’ in the Cyclic Sort. This will make two changes in our algorithm:
- In this problem, each number should be equal to its index, compared to
index + 1
in the Cyclic Sort. Therefore =>nums[i] == nums[nums[i]]
- Since the array will have ‘n’ numbers, which means array indices will range from 0 to ‘n-1’. Therefore, we will ignore the number ‘n’ as we can’t place it in the array, so =>
nums[i] < nums.length
- In this problem, each number should be equal to its index, compared to
- Say we are at index
i
. If we swap the number at indexi
to place it at the correct index, we can still have the wrong number at indexi
. This was true in Cyclic Sort too. It didn’t cause any problems in Cyclic Sort as over there, we made sure to place one number at its correct place in each step, but that wouldn’t be enough in this problem as we have one extra number due to the larger range. Therefore, we will not move to the next number after the swap until we have a correct number at the indexi
.
Code
Here is what our algorithm will look like:
1 | class Solution: |
Time complexity
The time complexity of the above algorithm is O(n). In the while
loop, although we are not incrementing the index i
when swapping the numbers, this will result in more than ‘n’ iterations of the loop, but in the worst-case scenario, the while
loop will swap a total of ‘n-1’ numbers and once a number is at its correct index, we will move on to the next number by incrementing i
. In the end, we iterate the input array again to find the first number missing from its index, so overall, our algorithm will take O(n) + O(n-1) + O(n) which is asymptotically equivalent to O(n).
Space complexity
The algorithm runs in constant space O(1).
Find all Missing Numbers (easy)
448. Find All Numbers Disappeared in an Array Design Gurus Educative.io
Problem Statement
We are given an unsorted array containing numbers taken from the range 1 to ‘n’. The array can have duplicates, which means some numbers will be missing. Find all those missing numbers.
Example 1:
1 | Input: [2, 3, 1, 8, 2, 3, 5, 1] |
Example 2:
1 | Input: |
Example 3:
1 | Input: |
Constraints:
n == nums.length
- 1 <= n <= 10^5
- 1 <= nums[i] <= n
Solution
This problem follows the Cyclic Sort pattern and shares similarities with Find the Missing Number with one difference. In this problem, there can be many duplicates whereas in ‘Find the Missing Number’ there were no duplicates and the range was greater than the length of the array.
However, we will follow a similar approach though as discussed in Find the Missing Number to place the numbers on their correct indices. Once we are done with the cyclic sort we will iterate the array to find all indices that are missing the correct numbers.
Code
Here is what our algorithm will look like:
1 | class Solution: |
Time complexity
The time complexity of the above algorithm is O(n)
Space complexity
Ignoring the space required for the output array, the algorithm runs in constant space O(1).
*Find the Duplicate Number (easy)
287. Find the Duplicate Number Design Gurus Educative.io
Problem Statement
We are given an unsorted array containing ‘n+1’ numbers taken from the range 1 to ‘n’. The array has only one duplicate but it can be repeated multiple times. Find that duplicate number without using any extra space. You are, however, allowed to modify the input array.
Example 1:
1 | Input: |
Example 2:
1 | Input: |
Example 3:
1 | Input: |
Constraints:
nums.length == n + 1
- 1 <= n <= 10^5
1 <= nums[i] <= n
- All the integers in
nums
appear only once except for precisely one integer which appears two or more times.
Solution
This problem follows the Cyclic Sort pattern and shares similarities with Find the Missing Number. Following a similar approach, we will try to place each number on its correct index. Since there is only one duplicate, if while swapping the number with its index both the numbers being swapped are same, we have found our duplicate!
Code
Here is what our algorithm will look like:
1 | # 按照之前几道题的思路写的如下: |
Time complexity
The time complexity of the above algorithm is O(n).
Space complexity
The algorithm runs in constant space O(1) but modifies the input array.
Similar Problems
Problem 1: Can we solve the above problem in O(1) space and without modifying the input array?
Solution: While doing the cyclic sort, we realized that the array will have a cycle due to the duplicate number and that the start of the cycle will always point to the duplicate number. This means that we can use the fast & the slow pointer method to find the duplicate number or the start of the cycle similar to Start of LinkedList Cycle(Pattern 4 problem 3)
1 | class Solution: |
The time complexity of the above algorithm is O(n) and the space complexity is O(1).
Find all Duplicate Numbers (easy)
442. Find All Duplicates in an Array Design Gurus Educative.io
Problem Statement
We are given an unsorted array containing ‘n’ numbers taken from the range 1 to ‘n’. The array has some duplicates, find all the duplicate numbers without using any extra space.
Example 1:
1 | Input: |
Example 2:
1 | Input: |
Constraints:
nums.length == n
- 1 <= n <= 10^5
1 <= nums[i] <= n
- Each element in
nums
appearsonce
ortwice
.
Solution
This problem follows the Cyclic Sort pattern and shares similarities with Find the Duplicate Number. Following a similar approach, we will place each number at its correct index. After that, we will iterate through the array to find all numbers that are not at the correct indices. All these numbers are duplicates.
Code
Here is what our algorithm will look like:
1 | class Solution: |
Time complexity
The time complexity of the above algorithm is O(n).
Space complexity
Ignoring the space required for storing the duplicates, the algorithm runs in constant space O(1).
Problem Challenge 1
Design Gurus Educative.io
Find the Corrupt Pair (easy)
We are given an unsorted array containing ‘n’ numbers taken from the range 1 to ‘n’. The array originally contained all the numbers from 1 to ‘n’, but due to a data error, one of the numbers got duplicated which also resulted in one number going missing. Find both these numbers.
Example 1:
1 | Input: [3, 1, 2, 5, 2] |
Example 2:
1 | Input: [3, 1, 2, 3, 6, 4] |
Constraints:
- 2 <= nums.length <= 10^4
- 1 <= nums[i] <= 10^4
Solution
This problem follows the Cyclic Sort pattern and shares similarities with Find all Duplicate Numbers. Following a similar approach, we will place each number at its correct index. Once we are done with the cyclic sort, we will iterate through the array to find the number that is not at the correct index. Since only one number got corrupted, the number at the wrong index is the duplicated number and the index itself represents the missing number.
Code
Here is what our algorithm will look like:
1 | class Solution: |
Time complexity
The time complexity of the above algorithm is O(n).
Space complexity
The algorithm runs in constant space O(1).
# Problem Challenge 2
41. First Missing Positive Design Gurus Educative.io
Find the Smallest Missing Positive Number (medium)
Given an unsorted array containing numbers, find the smallest missing positive number in it.
Note: Positive numbers start from ‘1’.
Example 1:
1 | Input: [-3, 1, 5, 4, 2] |
Example 2:
1 | Input: |
Example 3:
1 | Input: |
Example 4:
1 | Input: |
Constraints:
- 1 <= nums.length <= 10^5
- -231 <= nums[i] <= 2^31 - 1
Solution
This problem follows the Cyclic Sort pattern and shares similarities with Find the Missing Number with one big difference. In this problem, the numbers are not bound by any range so we can have any number in the input array.
However, we will follow a similar approach though as discussed in Find the Missing Number to place the numbers on their correct indices and ignore all numbers that are out of the range of the array (i.e., all negative numbers and all numbers greater than or equal to the length of the array). Once we are done with the cyclic sort we will iterate the array and the first index that does not have the correct number will be the smallest missing positive number!
Code
Here is what our algorithm will look like:
1 | class Solution: |
Time complexity
The time complexity of the above algorithm is O(n).
Space complexity
The algorithm runs in constant space O(1).
*Problem Challenge 3
Similar | 1539. Kth Missing Positive Number Design Gurus Educative.io
Find the First K Missing Positive Numbers (hard)
Given an unsorted array containing numbers and a number ‘k’, find the first ‘k’ missing positive numbers in the array.
Example 1:
1 | Input: |
Example 2:
1 | Input: |
Example 3:
1 | Input: |
Constraints:
- 1 <= nums.length <= 1000
- 1 <= nums[i] <= 1000
- 1 <= k <= 1000
- nums[i] < nums[j] for 1 <= i < j <= nums.length
Solution
This problem follows the Cyclic Sort pattern and shares similarities with Find the Smallest Missing Positive Number. The only difference is that, in this problem, we need to find the first ‘k’ missing numbers compared to only the first missing number.
We will follow a similar approach as discussed in Find the Smallest Missing Positive Number to place the numbers on their correct indices and ignore all numbers that are out of the range of the array. Once we are done with the cyclic sort we will iterate through the array to find indices that do not have the correct numbers.
If we are not able to find ‘k’ missing numbers from the array, we need to add additional numbers to the output array. To find these additional numbers we will use the length of the array. For example, if the length of the array is 4, the next missing numbers will be 4, 5, 6 and so on. One tricky aspect is that any of these additional numbers could be part of the array. Remember, while sorting, we ignored all numbers that are greater than or equal to the length of the array. So all indices that have the missing numbers could possibly have these additional numbers. To handle this, we must keep track of all numbers from those indices that have missing numbers. Let’s understand this with an example:
1 | nums: [2, 1, 3, 6, 5], k =2 |
After the cyclic sort our array will look like:
1 | nums: [1, 2, 3, 6, 5] |
From the sorted array we can see that the first missing number is ‘4’ (as we have ‘6’ on the fourth index) but to find the second missing number we need to remember that the array does contain ‘6’. Hence, the next missing number is ‘7’.
Code
Here is what our algorithm will look like:
1 | class Solution: |
Time complexity
The time complexity of the above algorithm is O(n + k), as the last two for
loops will run for O(n) and O(k) times respectively.
Space complexity
The algorithm needs O(k) space to store the extraNumbers
(the set).