Facebook Pixel

1064. Fixed Point

Problem Description

You are given an array arr of distinct integers sorted in ascending order. Your task is to find the smallest index i where the value at that index equals the index itself (i.e., arr[i] == i). If no such index exists, return -1.

For example:

  • If arr = [-10, -5, 0, 3, 7], the answer would be 3 because arr[3] = 3
  • If arr = [0, 2, 5, 8, 17], the answer would be 0 because arr[0] = 0
  • If arr = [-10, -5, 3, 4, 7, 9], the answer would be -1 because no index satisfies the condition

The solution uses binary search to efficiently find the answer. The key insight is that since the array is sorted and contains distinct integers:

  • If arr[mid] >= mid, then the fixed point (if it exists) must be at index mid or to the left of mid
  • If arr[mid] < mid, then the fixed point (if it exists) must be to the right of mid

This property allows us to eliminate half of the search space in each iteration, achieving O(log n) time complexity instead of the naive O(n) approach of checking every element.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key observation is that we're looking for a point where arr[i] = i. Let's think about what happens as we move through the array:

Since the array contains distinct integers in ascending order, when we examine any index mid:

  • If arr[mid] = mid, we've found a fixed point
  • If arr[mid] > mid, the value is "ahead" of its index
  • If arr[mid] < mid, the value is "behind" its index

Here's the crucial insight: because the array is sorted and contains distinct integers, the difference arr[i] - i can only increase or stay the same as we move right (it can never decrease by more than 1 per step).

Why? As we move from index i to i+1:

  • The index increases by exactly 1
  • The array value increases by at least 1 (since values are distinct and sorted)
  • Therefore, (arr[i+1] - (i+1)) >= (arr[i] - i)

This means if at some position mid we have arr[mid] < mid, then for all positions to the left of mid, we'll also have arr[j] < j. There's no way for a value to "catch up" to its index when moving left.

Similarly, if arr[mid] >= mid, there might be a fixed point at mid or to its left, but we need to check the leftmost such position to find the smallest index.

This monotonic property of arr[i] - i allows us to use binary search: we can safely eliminate half of the array in each step based on the comparison at the middle element, reducing our search from O(n) to O(log n).

Learn more about Binary Search patterns.

Solution Implementation

1class Solution:
2    def fixedPoint(self, arr: List[int]) -> int:
3        """
4        Find the smallest index i where arr[i] == i using binary search.
5
6        Args:
7            arr: A sorted array of distinct integers
8
9        Returns:
10            The smallest fixed point index, or -1 if no fixed point exists
11        """
12        # Binary search to find the first index where arr[mid] >= mid
13        # Feasible condition: arr[mid] >= mid
14        # Pattern: [false, false, ..., true, true, true]
15        left, right = 0, len(arr) - 1
16        first_true_index = -1
17
18        while left <= right:
19            mid = (left + right) // 2
20
21            if arr[mid] >= mid:
22                # Feasible: arr[mid] is at or ahead of mid
23                first_true_index = mid
24                right = mid - 1
25            else:
26                # Not feasible: arr[mid] < mid, search right
27                left = mid + 1
28
29        # Check if the found position is actually a fixed point (arr[i] == i)
30        if first_true_index != -1 and arr[first_true_index] == first_true_index:
31            return first_true_index
32        return -1
33
1class Solution {
2    /**
3     * Finds the smallest index i where arr[i] == i (fixed point).
4     * Uses binary search on a sorted array in ascending order.
5     *
6     * @param arr - sorted array of distinct integers in ascending order
7     * @return the smallest fixed point index, or -1 if none exists
8     */
9    public int fixedPoint(int[] arr) {
10        // Binary search to find the first index where arr[mid] >= mid
11        // Feasible condition: arr[mid] >= mid
12        // Pattern: [false, false, ..., true, true, true]
13        int left = 0;
14        int right = arr.length - 1;
15        int firstTrueIndex = -1;
16
17        while (left <= right) {
18            int mid = left + (right - left) / 2;
19
20            if (arr[mid] >= mid) {
21                // Feasible: arr[mid] is at or ahead of mid
22                firstTrueIndex = mid;
23                right = mid - 1;
24            } else {
25                // Not feasible: arr[mid] < mid, search right
26                left = mid + 1;
27            }
28        }
29
30        // Check if the found position is actually a fixed point (arr[i] == i)
31        if (firstTrueIndex != -1 && arr[firstTrueIndex] == firstTrueIndex) {
32            return firstTrueIndex;
33        }
34        return -1;
35    }
36}
37
1class Solution {
2public:
3    /**
4     * Find the smallest index i where arr[i] == i (fixed point)
5     * @param arr - sorted distinct integers array
6     * @return smallest fixed point index, or -1 if none exists
7     */
8    int fixedPoint(vector<int>& arr) {
9        // Binary search to find the first index where arr[mid] >= mid
10        // Feasible condition: arr[mid] >= mid
11        // Pattern: [false, false, ..., true, true, true]
12        int left = 0;
13        int right = arr.size() - 1;
14        int firstTrueIndex = -1;
15
16        while (left <= right) {
17            int mid = left + (right - left) / 2;
18
19            if (arr[mid] >= mid) {
20                // Feasible: arr[mid] is at or ahead of mid
21                firstTrueIndex = mid;
22                right = mid - 1;
23            } else {
24                // Not feasible: arr[mid] < mid, search right
25                left = mid + 1;
26            }
27        }
28
29        // Check if the found position is actually a fixed point (arr[i] == i)
30        if (firstTrueIndex != -1 && arr[firstTrueIndex] == firstTrueIndex) {
31            return firstTrueIndex;
32        }
33        return -1;
34    }
35};
36
1/**
2 * Finds the smallest index i where arr[i] === i (fixed point)
3 * Uses binary search on a sorted array in ascending order
4 * @param arr - A sorted array of distinct integers
5 * @returns The smallest fixed point index, or -1 if none exists
6 */
7function fixedPoint(arr: number[]): number {
8    // Binary search to find the first index where arr[mid] >= mid
9    // Feasible condition: arr[mid] >= mid
10    // Pattern: [false, false, ..., true, true, true]
11    let left = 0;
12    let right = arr.length - 1;
13    let firstTrueIndex = -1;
14
15    while (left <= right) {
16        const mid = Math.floor((left + right) / 2);
17
18        if (arr[mid] >= mid) {
19            // Feasible: arr[mid] is at or ahead of mid
20            firstTrueIndex = mid;
21            right = mid - 1;
22        } else {
23            // Not feasible: arr[mid] < mid, search right
24            left = mid + 1;
25        }
26    }
27
28    // Check if the found position is actually a fixed point (arr[i] == i)
29    if (firstTrueIndex !== -1 && arr[firstTrueIndex] === firstTrueIndex) {
30        return firstTrueIndex;
31    }
32    return -1;
33}
34

Solution Approach

The solution implements a binary search algorithm to find the smallest index where arr[i] == i.

Feasible Condition: arr[mid] >= mid - Is the value at mid at or ahead of the index?

This creates a pattern: [false, false, ..., true, true, true]

We want to find the first true index, then verify if it's exactly a fixed point (arr[i] == i, not just arr[i] >= i).

Binary Search Using Template:

  1. Initialize: left = 0, right = len(arr) - 1, first_true_index = -1

  2. Loop while left <= right:

    • Calculate mid = (left + right) // 2
    • If arr[mid] >= mid (feasible):
      • Record first_true_index = mid
      • Search left for potentially smaller index: right = mid - 1
    • Else (not feasible):
      • Search right: left = mid + 1
  3. Why this works: When arr[mid] >= mid:

    • If arr[mid] == mid, then mid could be our answer, but there might be a smaller fixed point to the left
    • If arr[mid] > mid, there still might be a fixed point to the left where the value "catches down" to the index
  4. Final check: After the loop, verify if first_true_index != -1 and arr[first_true_index] == first_true_index:

    • If true, return first_true_index as the smallest fixed point
    • If false, return -1 indicating no fixed point exists

The algorithm guarantees finding the smallest index because we continue searching left (right = mid - 1) even after finding a feasible position.

Time Complexity: O(log n) due to binary search Space Complexity: O(1) as we only use a constant amount of extra space

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the algorithm with arr = [-10, -5, 0, 3, 7].

We're looking for the smallest index i where arr[i] == i.

Initial Setup:

  • left = 0, right = 4, first_true_index = -1
  • Feasible condition: arr[mid] >= mid
  • Array visualization with indices:
Index: 0    1   2  3  4
Value: -10  -5  0  3  7

Iteration 1:

  • left = 0, right = 4
  • mid = (0 + 4) // 2 = 2
  • Check arr[2] = 0 >= mid = 2? → 0 >= 2 is FALSE
  • Not feasible, search right: left = 3

Iteration 2:

  • left = 3, right = 4
  • mid = (3 + 4) // 2 = 3
  • Check arr[3] = 3 >= mid = 3? → 3 >= 3 is TRUE
  • Feasible! Record first_true_index = 3
  • Search left for smaller: right = 2

Iteration 3:

  • left = 3, right = 2
  • left > right, loop terminates

Final Check:

  • first_true_index = 3
  • Check if arr[3] == 3? → Yes!
  • Return 3

The algorithm correctly identifies that index 3 is the smallest (and only) index where the value equals the index.

Why Binary Search Works Here: Notice how at each step, we eliminated half of the search space:

  • When arr[2] = 0 < 2, we knew indices 0, 1, 2 couldn't be fixed points (values are too small)
  • When arr[3] = 3 >= 3, we found our potential answer and continued searching left for any smaller fixed point

The sorted and distinct nature of the array ensures that once values fall behind indices (arr[i] < i), they can never catch up when moving left, making binary search possible.

Time and Space Complexity

Time Complexity: O(log n)

The algorithm uses binary search to find the fixed point (where arr[i] == i). In each iteration, the search space is halved by comparing the middle element with its index:

  • If arr[mid] >= mid, the fixed point (if it exists) must be in the left half including mid, so we set right = mid
  • If arr[mid] < mid, the fixed point must be in the right half, so we set left = mid + 1

Since the search space is reduced by half in each iteration, and we continue until left >= right, the total number of iterations is O(log n) where n is the length of the array.

Space Complexity: O(1)

The algorithm only uses a constant amount of extra space for the variables left, right, and mid. No additional data structures are created that depend on the input size, making the space complexity constant.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Using the Wrong Binary Search Template

The Pitfall: Using while left < right with right = mid instead of the standard template.

# Alternative template (not recommended)
while left < right:
    mid = (left + right) >> 1
    if arr[mid] >= mid:
        right = mid
    else:
        left = mid + 1
return left if arr[left] == left else -1

The Solution: Use the standard template with while left <= right and first_true_index:

first_true_index = -1
while left <= right:
    mid = (left + right) // 2
    if arr[mid] >= mid:
        first_true_index = mid
        right = mid - 1
    else:
        left = mid + 1
return first_true_index if first_true_index != -1 and arr[first_true_index] == first_true_index else -1

2. Returning Early When arr[mid] == mid

The Pitfall: Immediately returning mid when arr[mid] == mid is found.

# INCORRECT approach
while left <= right:
    mid = (left + right) // 2
    if arr[mid] == mid:
        return mid  # Wrong! This might not be the smallest index

Why it's wrong: This fails to find the smallest index. For arr = [0, 1, 5, 8], if we check mid = 1 and find arr[1] == 1, we'd return 1, missing index 0.

The Solution: Always search left (right = mid - 1) when feasible to find the smallest index.

3. Forgetting the Final Validation

The Pitfall: Not checking if first_true_index is actually a fixed point.

# INCORRECT approach
return first_true_index  # Wrong! arr[first_true_index] might be > first_true_index

Why it's wrong: The feasible condition is arr[mid] >= mid, not arr[mid] == mid. The first feasible index might have arr[i] > i, not arr[i] == i.

The Solution: Always validate:

if first_true_index != -1 and arr[first_true_index] == first_true_index:
    return first_true_index
return -1

4. Integer Overflow in Mid Calculation

The Pitfall: Using mid = (left + right) / 2 could cause overflow in languages with fixed integer sizes.

The Solution: Use mid = left + (right - left) / 2. Python handles large integers gracefully, but this is good practice for portable code.

Loading...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which algorithm should you use to find a node that is close to the root of the tree?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More