2089. Find Target Indices After Sorting Array
Problem Description
You are given an integer array nums
(0-indexed) and a target value target
.
The task is to:
- Sort the array
nums
in non-decreasing order (ascending order) - Find all indices where the value equals
target
in the sorted array - Return these indices as a list
Key points:
- A target index is defined as an index
i
wherenums[i] == target
- The array must be sorted first before finding the target indices
- If no elements equal the target, return an empty list
- The returned list of indices must be in increasing order (which naturally happens since we're checking indices sequentially)
For example:
- If
nums = [1, 2, 5, 2, 3]
andtarget = 2
- After sorting:
nums = [1, 2, 2, 3, 5]
- The value
2
appears at indices1
and2
- Return
[1, 2]
The solution approach is straightforward:
- Sort the array using
nums.sort()
- Use list comprehension to iterate through the sorted array with
enumerate()
to get both index and value - Include indices where the value equals the target:
[i for i, v in enumerate(nums) if v == target]
Intuition
The problem asks us to find indices of a target value after sorting. The most direct approach is to do exactly what the problem states: sort first, then find the indices.
Why does this work? When we sort an array, all occurrences of the same value will be grouped together consecutively. This means if the target value exists in the array, all instances of it will appear in a continuous block after sorting.
For example, if we have [5, 2, 3, 2, 1]
with target 2
, after sorting we get [1, 2, 2, 3, 5]
. Notice how both 2
s are now adjacent at indices 1
and 2
.
Since we're iterating through the sorted array from left to right (index 0 to n-1), and checking each element against the target, we naturally collect the indices in increasing order. This eliminates the need for any additional sorting of the result.
The beauty of this approach lies in its simplicity - we don't need to overthink it. We could try to count elements less than the target to predict where it would appear after sorting, but that would be more complex and error-prone. Instead, we:
- Sort the array (which Python does efficiently with
sort()
) - Walk through it once with
enumerate()
to get index-value pairs - Filter for values that match our target
This gives us a clean one-liner solution after sorting: [i for i, v in enumerate(nums) if v == target]
.
Learn more about Binary Search and Sorting patterns.
Solution Approach
The implementation follows a two-step process:
Step 1: Sort the array
nums.sort()
This uses Python's built-in sort()
method which sorts the list in-place in non-decreasing order. The time complexity of this operation is O(n log n)
where n
is the length of the array.
Step 2: Find and collect target indices
return [i for i, v in enumerate(nums) if v == target]
This step uses a list comprehension with enumerate()
to achieve multiple things simultaneously:
enumerate(nums)
creates pairs of(index, value)
for each element in the sorted arrayfor i, v in enumerate(nums)
unpacks each pair into indexi
and valuev
if v == target
filters to only include indices where the value matches our target- The list comprehension
[i ...]
collects all matching indices into a new list
The enumerate function iterates through the array exactly once, making this step O(n)
in time complexity.
Why this works: After sorting, if the target exists in the array, all occurrences will be consecutive. As we iterate from index 0 to n-1, we encounter these occurrences in order, naturally producing a sorted list of indices.
Overall Complexity:
- Time Complexity:
O(n log n)
dominated by the sorting step - Space Complexity:
O(k)
wherek
is the number of occurrences of the target (for the output list)
The solution is elegant in its simplicity - it directly implements what the problem asks for without any unnecessary complications.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to see how the solution works step by step.
Example: nums = [5, 3, 2, 3, 1]
and target = 3
Step 1: Sort the array
- Original array:
[5, 3, 2, 3, 1]
- After
nums.sort()
:[1, 2, 3, 3, 5]
- Notice how both occurrences of
3
are now adjacent at positions 2 and 3
Step 2: Find target indices using enumerate
Let's trace through the list comprehension [i for i, v in enumerate(nums) if v == target]
:
Index (i) | Value (v) | v == 3? | Action |
---|---|---|---|
0 | 1 | False | Skip |
1 | 2 | False | Skip |
2 | 3 | True | Add index 2 to result |
3 | 3 | True | Add index 3 to result |
4 | 5 | False | Skip |
Result: [2, 3]
The indices are automatically in increasing order because we iterate through the sorted array from left to right. Both occurrences of the target value 3
are found at indices 2 and 3 in the sorted array.
Edge Case Example: nums = [4, 1, 2]
and target = 5
- After sorting:
[1, 2, 4]
- No element equals 5, so the list comprehension produces an empty list
[]
This walkthrough demonstrates how the two-step approach (sort, then find) efficiently solves the problem with clean, readable code.
Solution Implementation
1class Solution:
2 def targetIndices(self, nums: List[int], target: int) -> List[int]:
3 """
4 Find all indices of target value in sorted array.
5
6 Args:
7 nums: List of integers to search through
8 target: The target value to find indices for
9
10 Returns:
11 List of indices where target appears in the sorted array
12 """
13 # Sort the array in ascending order (modifies in-place)
14 nums.sort()
15
16 # Use list comprehension to collect all indices where value equals target
17 # enumerate() provides (index, value) pairs for each element
18 result = [i for i, v in enumerate(nums) if v == target]
19
20 return result
21
1class Solution {
2 /**
3 * Find all indices where target would appear in a sorted array.
4 *
5 * @param nums The input array of integers
6 * @param target The target value to find indices for
7 * @return A list of indices where target appears after sorting
8 */
9 public List<Integer> targetIndices(int[] nums, int target) {
10 // Sort the array in ascending order
11 Arrays.sort(nums);
12
13 // Initialize result list to store target indices
14 List<Integer> result = new ArrayList<>();
15
16 // Iterate through sorted array to find all occurrences of target
17 for (int i = 0; i < nums.length; i++) {
18 // If current element equals target, add its index to result
19 if (nums[i] == target) {
20 result.add(i);
21 }
22 }
23
24 return result;
25 }
26}
27
1class Solution {
2public:
3 vector<int> targetIndices(vector<int>& nums, int target) {
4 // Sort the array in ascending order
5 sort(nums.begin(), nums.end());
6
7 // Initialize result vector to store indices of target elements
8 vector<int> result;
9
10 // Iterate through the sorted array to find all occurrences of target
11 for (int i = 0; i < nums.size(); ++i) {
12 // If current element equals target, add its index to result
13 if (nums[i] == target) {
14 result.push_back(i);
15 }
16 }
17
18 // Return the list of indices where target appears in sorted array
19 return result;
20 }
21};
22
1/**
2 * Finds all indices of target value in sorted array
3 * @param nums - Array of integers to search through
4 * @param target - Target value to find indices for
5 * @returns Array of indices where target appears in sorted array
6 */
7function targetIndices(nums: number[], target: number): number[] {
8 // Sort the array in ascending order
9 nums.sort((a: number, b: number) => a - b);
10
11 // Initialize result array to store indices
12 const result: number[] = [];
13
14 // Iterate through sorted array to find all occurrences of target
15 for (let i = 0; i < nums.length; i++) {
16 if (nums[i] === target) {
17 result.push(i);
18 }
19 }
20
21 return result;
22}
23
Time and Space Complexity
Time Complexity: O(n log n)
- The
nums.sort()
operation uses Python's Timsort algorithm, which has a time complexity ofO(n log n)
wheren
is the length of the array - The list comprehension
[i for i, v in enumerate(nums) if v == target]
iterates through all elements once, takingO(n)
time - The overall time complexity is dominated by the sorting step:
O(n log n) + O(n) = O(n log n)
Space Complexity: O(n)
- The
nums.sort()
operation sorts the list in-place, requiringO(1)
auxiliary space in Python (though technically Timsort can use up toO(n)
space in worst case for its merge operations) - The list comprehension creates a new list to store the result indices, which in the worst case (when all elements equal target) can contain
n
elements, requiringO(n)
space - Therefore, the overall space complexity is
O(n)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Assuming the Original Array Indices are Needed
A common misunderstanding is thinking we need to track the indices from the original unsorted array. Some might try to create index mappings before sorting or use more complex data structures.
Why it's wrong: The problem specifically asks for indices in the sorted array, not the original array.
Incorrect approach example:
# Wrong: Trying to preserve original indices
original_indices = [(nums[i], i) for i in range(len(nums))]
original_indices.sort()
# This tracks wrong indices!
Correct understanding: Simply sort first, then find indices in the sorted array.
2. Using Binary Search Unnecessarily
Since the array is sorted, some might think binary search is required to find the target efficiently.
Why it's a pitfall: While binary search can find one occurrence of the target in O(log n), you still need to check neighboring elements to find all occurrences, which could be O(n) in the worst case (when all elements equal target). The simple linear scan is cleaner and has the same worst-case complexity.
Overly complex approach:
# Unnecessary complexity with binary search
import bisect
nums.sort()
left = bisect.bisect_left(nums, target)
right = bisect.bisect_right(nums, target)
return list(range(left, right))
Better approach: The simple list comprehension is more readable and equally efficient.
3. Forgetting that sort() Modifies In-Place
Some might not realize that nums.sort()
modifies the original list and try to use the unsorted nums
afterward.
Incorrect pattern:
nums.sort()
# Later trying to use original order
return [i for i, v in enumerate(original_nums) if v == target] # original_nums doesn't exist!
Solution: If you need to preserve the original array for any reason, create a copy first:
sorted_nums = sorted(nums) # Creates a new sorted list
# OR
sorted_nums = nums.copy()
sorted_nums.sort()
4. Not Handling Edge Cases Mentally
While the given solution handles these correctly, it's important to verify:
- Empty array:
nums = []
returns[]
- Target not in array: returns
[]
- All elements equal target: returns
[0, 1, 2, ..., n-1]
- Single element: works correctly
The beauty of the list comprehension approach is that it naturally handles all these cases without special checks.
What data structure does Breadth-first search typically uses to store intermediate states?
Recommended Readings
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!