Skip to content
← All posts

Special Array With X Elements Greater Than or Equal X: Sorting and Counting

6 min read
leetcodeproblemeasyarraysbinary-searchsorting

You are given an array nums of non-negative integers. The array is called "special" if there exists a value x such that exactly x elements in nums are greater than or equal to x. You need to return that x, or -1 if no such value exists.

This is LeetCode 1608: Special Array With X Elements Greater Than or Equal X. It is an easy problem, but it teaches a pattern that shows up in more advanced sorting and counting problems.

0[0]1[1]3[2]5[3]6[4]3 elements >= 3x = 3 works!
Sorted array [0, 1, 3, 5, 6]. With x = 3, exactly 3 elements are >= 3 (highlighted in green). The array is special.

Why this problem matters

The Special Array problem is a clean example of the "sort first, then reason about suffix counts" pattern. After sorting, the number of elements >= some threshold is just the length of a suffix of the array. This idea of converting a counting problem into a position lookup in a sorted array appears in problems like H-Index, finding percentiles, and various binary search on answer tasks.

If you internalize how sorting turns "count elements satisfying a condition" into "find the right index," you will recognize this trick in harder problems without hesitation.

The key insight

Once the array is sorted in ascending order, the number of elements >= any value x is simply n - i, where i is the first index whose value is >= x. So for each candidate x from 1 to n, you just need to check whether the count of elements >= x is exactly x.

After sorting, you can iterate through candidates and use the sorted positions to count efficiently. For each index i in the sorted array, the number of elements from index i to the end is n - i. If n - i equals the value at that boundary (and the previous element does not also satisfy the condition), you have found your x.

The solution

def specialArray(nums):
    nums.sort()
    n = len(nums)

    for x in range(1, n + 1):
        count = 0
        for val in nums:
            if val >= x:
                count += 1
        if count == x:
            return x

    return -1

This brute force approach checks every candidate x from 1 to n and counts how many elements are >= x. It works, but it is O(n^2). We can do better by sorting first and using the sorted order to count in O(1) per candidate.

def specialArray(nums):
    nums.sort()
    n = len(nums)

    for x in range(1, n + 1):
        idx = bisect_left(nums, x)
        count = n - idx
        if count == x:
            return x

    return -1

After sorting, bisect_left(nums, x) gives the first index where a value >= x could appear. The count of elements >= x is then n - idx. If that count equals x, we found our answer.

You need from bisect import bisect_left at the top of the file.

The loop runs at most n iterations, and each bisect_left call is O(log n), so the total time is O(n log n) for sorting plus O(n log n) for the loop. That simplifies to O(n log n).

You can also solve this without bisect_left by iterating through the sorted array once and checking at each index whether n - i could be the answer. This avoids the binary search entirely and gives a clean O(n log n) solution dominated by the sort.

Visual walkthrough

Let's trace through the array [0, 1, 3, 5, 6] (already sorted for clarity) and check each candidate value of x.

Step 1: Sort the array. Try x = 5.

0[0]1[1]3[2]5[3]6[4]x = 5: 2 elements >= 5 (need exactly 5)

Only 2 elements are >= 5 (values 5 and 6), but we need exactly 5. Count < x, so x = 5 does not work.

Step 2: Try x = 4.

0[0]1[1]3[2]5[3]6[4]x = 4: 2 elements >= 4 (need exactly 4)

Still only 2 elements are >= 4 (values 5 and 6). Count is 2, not 4. Move on.

Step 3: Try x = 3.

0[0]1[1]3[2]5[3]6[4]x = 3: 3 elements >= 3 (match!)

Three elements are >= 3 (values 3, 5, and 6). Count equals x. We found it!

Step 4: Verify no other x works. Try x = 2.

0[0]1[1]3[2]5[3]6[4]x = 2: 3 elements >= 2 (need exactly 2)

Three elements are >= 2, but we need exactly 2. Count is 3, not 2. Does not work.

Step 5: Try x = 1.

0[0]1[1]3[2]5[3]6[4]x = 1: 4 elements >= 1 (need exactly 1)

Four elements are >= 1, but we need exactly 1. The answer is x = 3, which we already found.

The walkthrough shows that most values of x do not produce an exact match between the count and x itself. Only x = 3 works, because exactly 3 elements (3, 5, and 6) are >= 3. The key observation is that as x increases, the count of elements >= x can only stay the same or decrease. This monotonic relationship is why at most one valid x can exist.

Complexity analysis

ApproachTimeSpace
Brute force (check each x, scan array)O(n^2)O(1)
Sort + binary search per candidateO(n log n)O(1)
Sort + single passO(n log n)O(1)

Time: The dominant cost is sorting, which is O(n log n). After that, the counting step is at most O(n) with a single pass, or O(n log n) with binary search per candidate. Either way, O(n log n) total.

Space: O(1) extra space if you sort in place. Python's sort() is in-place, so no additional allocation beyond the sort's internal overhead.

The building blocks

1. Sort then reason about positions

Sorting transforms a counting problem into an index problem. After sorting, "how many elements are >= x?" becomes "where does x first appear (or would be inserted)?" The count is just the suffix length from that position.

nums.sort()
idx = bisect_left(nums, x)
count = len(nums) - idx

This pattern appears in H-Index, percentile calculations, and any problem where you need frequency counts relative to a threshold.

2. Monotonic candidate search

As x increases, the count of elements >= x can only decrease (or stay the same). This monotonic property means at most one value of x can satisfy count == x. You do not need to worry about multiple answers. You can also exploit this monotonicity to use binary search on x itself for an even more direct solution.

for x in range(1, n + 1):
    if count_gte(nums, x) == x:
        return x
return -1

Edge cases

  • All zeros: nums = [0, 0, 0]. No value of x from 1 to 3 produces a match, so return -1.
  • Single element: nums = [1]. Check x = 1: one element is >= 1, so return 1. But nums = [0] returns -1 because zero elements are >= 1.
  • All elements equal: nums = [3, 3, 3]. For x = 3, all 3 elements are >= 3, so return 3. But nums = [2, 2, 2] returns -1 because for x = 2 there are 3 elements >= 2 (not 2), and for x = 3 there are 0 elements >= 3.
  • Already special at x = n: nums = [5, 5, 5, 5, 5]. For x = 5, all 5 elements are >= 5. Return 5.

From understanding to recall

This problem is short and the code is only a few lines. That makes it tempting to skip drilling it. But the pattern it uses, sorting an array and reasoning about suffix counts, shows up in more complex problems where you will not have time to re-derive the approach from scratch. If you have practiced "sort, find the insertion point, compute the suffix length" as a building block, you will recognize it instantly when it appears inside a harder problem like H-Index or Split Array Largest Sum.

Spaced repetition turns that recognition from "I think I remember this" into automatic recall. You type the solution from scratch at increasing intervals until the pattern is in your fingers.

Related posts

  • Binary Search - The binary search pattern that powers the bisect_left lookup used in the optimal solution
  • Koko Eating Bananas - Another problem where sorting and binary search on the answer space combine to find a threshold value
  • Contains Duplicate - A simpler array problem that introduces the "process a sorted array" building block

The Special Array problem is a small problem with a useful lesson: sorting unlocks fast counting. Once you see that n - i gives the suffix count in a sorted array, a whole category of threshold and counting problems becomes approachable. CodeBricks breaks this down into the individual building blocks (sort + position lookup, monotonic candidate search) so you can drill each one independently and combine them fluently.