Back to Arrays
Q73Question 73 of 109

Order-agnostic Binary Search (Search a Sorted Array When the Order Is Unknown)

Key Concepts
  • Detect ascending or descending by comparing arr[start] with arr[end] before the loop.
  • Run standard binary search, but flip the comparison logic when the array is descending.
  • The direction detection is a single comparison done once, keeping the search O(log n).
  • Use the overflow-safe midpoint: mid = start + (end - start) / 2.
  • If all values are equal, direction is irrelevant and either branch finds the key.
  • This is the first problem in the Modified Binary Search pattern.
  • The order detection generalizes to problems where input direction is not guaranteed.

Definition

Detect ascending or descending once by comparing the endpoints, then binary-search with the comparison flipped to match the direction.
  • Direction detection – compare arr[start] with arr[end] to determine whether the array is ascending or descending.
  • Ascending search – if key < arr[mid], move end = mid - 1; if key > arr[mid], move start = mid + 1.
  • Descending search – flip the logic: if key > arr[mid], move end = mid - 1; if key < arr[mid], move start = mid + 1.
  • Single detection – direction is checked once before the loop, so the overall complexity stays O(log n).
  • Space – O(1) for the iterative form.

At the National Bank of India, sorted ledgers of daily closing balances arrive from two feeds: one oldest-to-newest and one newest-to-oldest. When Rajesh looks up a specific balance, he first peeks at the top and bottom rows to learn which way the ledger runs, then binary-searches with the comparisons adjusted for that direction.

Understanding the Concepts

Order-agnostic binary search works on a sorted array whose direction, ascending or descending, is not known in advance. The algorithm first detects the direction by comparing the first and last elements, then runs standard binary search with the comparison logic adjusted to match the detected direction.

JAVA
package com.bank.core;

public class OrderAgnosticBinarySearch {

    public static int search(int[] arr, int key) {
        int start = 0;
        int end = arr.length - 1;
        boolean ascending = arr[start] < arr[end];

        while (start <= end) {
            int mid = start + (end - start) / 2;

            if (arr[mid] == key) {
                return mid;
            }

            if (ascending) {
                if (key < arr[mid]) end = mid - 1;
                else start = mid + 1;
            } else {
                if (key > arr[mid]) end = mid - 1;
                else start = mid + 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] ascending = {1000, 2000, 3000, 4000, 5000};
        int[] descending = {5000, 4000, 3000, 2000, 1000};

        System.out.println("Ascending, find 3000: " + search(ascending, 3000));
        System.out.println("Descending, find 3000: " + search(descending, 3000));
    }
}
TEXT
Ascending, find 3000: 2
Descending, find 3000: 2

How does direction detection work?

Direction is detected by a single comparison of the endpoints: arr[start] < arr[end] means ascending, otherwise descending. This check costs O(1) and is done once before the loop.

JAVA
package com.bank.core;

public class DirectionDetection {

    public static void main(String[] args) {
        int[] asc = {1000, 2000, 3000, 4000, 5000};
        int[] desc = {5000, 4000, 3000, 2000, 1000};
        int[] equal = {3000, 3000, 3000};

        System.out.println("asc[0] < asc[4]: " + (asc[0] < asc[4]));      // true
        System.out.println("desc[0] < desc[4]: " + (desc[0] < desc[4]));   // false
        System.out.println("equal[0] < equal[2]: " + (equal[0] < equal[2])); // false (irrelevant)
    }
}
TEXT
asc[0] < asc[4]: true
desc[0] < desc[4]: false
equal[0] < equal[2]: false

How does the comparison flip work?

In an ascending array, when key < arr[mid], the key is to the left, so end = mid - 1. In a descending array, when key < arr[mid], the key is to the right (because smaller values are on the right in a descending array), so start = mid + 1. The comparison operators are swapped based on direction.

JAVA
package com.bank.core;

public class ComparisonFlip {

    public static int search(int[] arr, int key) {
        int start = 0, end = arr.length - 1;
        boolean asc = arr[start] < arr[end];
        while (start <= end) {
            int mid = start + (end - start) / 2;
            if (arr[mid] == key) return mid;
            if (asc) {
                System.out.println("  ASC: mid=" + mid + " arr[mid]=" + arr[mid]
                        + (key < arr[mid] ? " key left" : " key right"));
                if (key < arr[mid]) end = mid - 1; else start = mid + 1;
            } else {
                System.out.println("  DESC: mid=" + mid + " arr[mid]=" + arr[mid]
                        + (key > arr[mid] ? " key left" : " key right"));
                if (key > arr[mid]) end = mid - 1; else start = mid + 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        System.out.println("Searching descending [5000,4000,3000,2000,1000] for 4000:");
        System.out.println("Found at: " + search(new int[]{5000, 4000, 3000, 2000, 1000}, 4000));
    }
}
TEXT
Searching descending [5000,4000,3000,2000,1000] for 4000:
  DESC: mid=2 arr[mid]=3000 key left
Found at: 1

What if all values are equal?

If every element is the same, direction detection returns false (not ascending), but it does not matter because the key either equals every element (found immediately) or does not exist. Either branch handles it correctly.

JAVA
package com.bank.core;

public class AllEqualCase {

    public static int search(int[] arr, int key) {
        int start = 0, end = arr.length - 1;
        boolean asc = arr[start] < arr[end];
        while (start <= end) {
            int mid = start + (end - start) / 2;
            if (arr[mid] == key) return mid;
            if (asc) { if (key < arr[mid]) end = mid - 1; else start = mid + 1; }
            else { if (key > arr[mid]) end = mid - 1; else start = mid + 1; }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] allSame = {3000, 3000, 3000, 3000};
        System.out.println("Find 3000: " + search(allSame, 3000));
        System.out.println("Find 5000: " + search(allSame, 5000));
    }
}
TEXT
Find 3000: 1
Find 5000: -1

What about the overflow-safe midpoint?

Always compute mid = start + (end - start) / 2 instead of (start + end) / 2 to avoid integer overflow when both indices are large. This applies to every binary search variant.

JAVA
package com.bank.core;

public class MidSafety {

    public static void main(String[] args) {
        int start = 1_500_000_000, end = 2_000_000_000;
        int bad = (start + end) / 2;
        int good = start + (end - start) / 2;
        System.out.println("Unsafe: " + bad);
        System.out.println("Safe:   " + good);
    }
}
TEXT
Unsafe: -397483648
Safe:   1750000000

What are the edge cases?

Edge cases include a single-element array, a two-element ascending array, a two-element descending array, and searching for a value not present.

JAVA
package com.bank.core;

public class OrderAgnosticEdgeCases {

    public static int search(int[] arr, int key) {
        int start = 0, end = arr.length - 1;
        boolean asc = arr[start] < arr[end];
        while (start <= end) {
            int mid = start + (end - start) / 2;
            if (arr[mid] == key) return mid;
            if (asc) { if (key < arr[mid]) end = mid - 1; else start = mid + 1; }
            else { if (key > arr[mid]) end = mid - 1; else start = mid + 1; }
        }
        return -1;
    }

    public static void main(String[] args) {
        System.out.println("Single: " + search(new int[]{5000}, 5000));
        System.out.println("Two asc: " + search(new int[]{1000, 2000}, 2000));
        System.out.println("Two desc: " + search(new int[]{2000, 1000}, 1000));
        System.out.println("Not found: " + search(new int[]{1000, 3000, 5000}, 4000));
    }
}
TEXT
Single: 0
Two asc: 1
Two desc: 1
Not found: -1

How does this relate to other Modified Binary Search problems?

Order-agnostic binary search is the first and simplest Modified Binary Search problem. It introduces the pattern of adapting standard binary search to a slightly different situation. The same idea of adjusting comparisons appears in ceiling/floor finding, number range, and bitonic array search.

What should a senior engineer know?

A senior engineer should note that the direction detection from endpoints assumes at least two distinct values. If only one value exists, direction is irrelevant and the standard match check handles it. The single-check detection keeps the algorithm at O(log n) total with O(1) space. This problem sets the foundation for every Modified Binary Search variant that follows.

Visual Overview

DIAGRAM
Descending Array: [5000, 4000, 3000, 2000, 1000]
Key: 2000

Step 0: Detect direction
  arr[0]=5000 > arr[4]=1000 → descending

Step 1: start=0 end=4 mid=2  arr[2]=3000
  key=2000 < arr[2]=3000
  Descending → smaller values are RIGHT → start = mid + 1 = 3

Step 2: start=3 end=4 mid=3  arr[3]=2000
  key=2000 == arr[3]=2000 → FOUND at index 3

┌─────────────────────────────────────────────┐
│ Direction detection: one comparison, O(1)    │
│ Binary search: O(log n) with flipped logic   │
│ Total: O(log n) time, O(1) space             │
└─────────────────────────────────────────────┘

Key Takeaway

Order-agnostic binary search is the opening problem of the Modified Binary Search pattern. The array is sorted but the direction is unknown, so a single comparison of the two endpoints detects whether it ascends or descends. Then a normal binary search runs with the comparison logic flipped to match: in ascending order the key moves right when it is larger, and in descending order the key moves right when it is smaller. Because the detection is just one comparison, the whole search stays logarithmic.

The important details are using the overflow-safe midpoint and getting the flipped comparisons right for descending arrays. In an ascending array, key < arr[mid] means the key is to the left. In a descending array, key < arr[mid] means the key is to the right, because smaller values sit on the right side. Swapping the direction of movement based on the detected order is the only change from standard binary search.

At the National Bank of India, Rajesh uses this to search sorted ledgers of daily closing balances that arrive from two different feeds, one in ascending order and one in descending. Detecting the direction from the endpoints and adjusting the search logic lets operations locate a specific balance instantly regardless of the feed's order.

This problem sets the foundation for every Modified Binary Search variant that follows: ceiling, floor, number range, bitonic search, and rotated array search all build on the idea of adapting the standard binary search decision to a modified situation.

Remember one sentence: detect ascending or descending once by comparing the endpoints, then binary-search with the comparison flipped to match the direction.

---

Share
Use ← → arrow keys to navigate