Back to Arrays
Q78Question 78 of 109

Bitonic Array Maximum (Find the Peak of an Array That Rises Then Falls)

Key Concepts
  • Array traversal, search, and manipulation
  • Common patterns: two-pointer, prefix sum, sliding window
  • Find max/min, reverse, rotate, remove duplicates
  • Time complexity: O(n) traversal, O(1) access by index
  • We set `start = 0` and `end = n - 1`.
  • In the loop `mid = start + (end - start) / 2`.
  • We compare `arr[mid]` with `arr[mid + 1]`: if `arr[mid] > arr[mid + 1]` we are on the descending side so the peak is at `mid` or to its left, so `end = mid`; otherwise we are ascending so the peak is to the right, so `start = mid + 1`.

Definition

Compare mid with its right neighbour; climbing means go right, falling means go left, and the pointers meet at the peak.

Bitonic Array Maximum is a Modified Binary Search problem. A bitonic array rises to one peak and then falls. We binary-search, and at each step we compare the middle element with its right neighbour: if the middle is smaller than its right neighbour we are on the rising side and move right, otherwise we are on the falling side and move left. The pointers converge exactly on the peak.

At the National Bank of India, a single trading day's intraday price of Rajesh's stock rises to a daily high and then falls. Stored as a bitonic array, we find the daily high by binary search: if the current price is still climbing we look right, if it is already falling we look left, until we land on the high.

Understanding the Concepts

What is the problem?

Bitonic Array Maximum (Find the Peak of an Array That Rises Then Falls). A bitonic array strictly increases to a single maximum and then strictly decreases. Find the maximum value using binary search. Explain how comparing the middle element with its right neighbour tells you which side the peak is on.

How does the approach work?

We set start = 0 and end = n - 1. In the loop mid = start + (end - start) / 2. We compare arr[mid] with arr[mid + 1]: if arr[mid] > arr[mid + 1] we are on the descending side so the peak is at mid or to its left, so end = mid; otherwise we are ascending so the peak is to the right, so start = mid + 1. For example, if (arr[mid] > arr[mid + 1]) end = mid; else start = mid + 1;. The loop condition is start < end, and when it ends start == end points at the peak, so we return arr[start].

Note we do not use start <= end here; we use start < end because we are converging two pointers to a single index rather than looking for an exact value, and we never let mid + 1 run out of bounds because mid is always strictly less than end when start < end.

A senior nuance is that this finds the index of the peak, which is the pivot for the related Search Bitonic Array problem, so solving this cleanly is a building block. The strictly-increasing-then-strictly-decreasing assumption guarantees a single peak and no plateaus, which is what makes the neighbour comparison decisive. Complexity is O(log n) time and O(1) space.

What is the banking use case?

Problem 1 — The National Bank of India records a single trading day's intraday prices for Rajesh's stock as a bitonic array that rises to the day's high and then falls, and the analytics team needs the daily high quickly. This is exactly how Bitonic Array Maximum works: find the single peak.
Problem 2 — Scanning the whole day's ticks is wasteful when there can be thousands of them. This is why we binary-search by comparing each middle tick with its right neighbour to decide which side the high is on.

The code defines a PeakPriceService exposing dailyHigh(prices) returning the peak price. A Demo finds the daily high of a bitonic price series and logs it.

How do you implement this in Java?

JAVA
// ─── File: src/main/java/com/bank/peak/service/PeakPriceService.java ───
package com.bank.peak.service;

import java.util.logging.Logger;

// Finds the peak of a bitonic (rise-then-fall) price array.
public class PeakPriceService {
    private static final Logger log = Logger.getLogger(PeakPriceService.class.getName());

    public int dailyHigh(int[] prices) {
        int start = 0, end = prices.length - 1;
        while (start < end) {
            int mid = start + (end - start) / 2;
            if (prices[mid] > prices[mid + 1]) end = mid;      // falling: peak is here or left
            else start = mid + 1;                               // rising: peak is to the right
        }
        final int peak = prices[start];
        log.info(() -> "Daily high at index " + start + " = " + peak);
        return peak; // start == end points at the peak
    }
}
JAVA
// ─── File: src/main/java/com/bank/peak/PeakPriceApplication.java ───
package com.bank.peak;

import com.bank.peak.service.PeakPriceService;
import java.util.logging.Logger;

public class PeakPriceApplication {
    private static final Logger log = Logger.getLogger(PeakPriceApplication.class.getName());

    public static void main(String[] args) {
        PeakPriceService service = new PeakPriceService();
        int[] prices = {101, 108, 121, 140, 135, 119, 104};
        log.info("Rajesh SAV2001 stock daily high: " + service.dailyHigh(prices));
    }
}

What is the project structure?

DIAGRAM
peak-price-service/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/com/bank/peak/
│   │   │   ├── PeakPriceApplication.java         (main class)
│   │   │   └── service/
│   │   │       └── PeakPriceService.java
│   │   └── resources/
│   │       └── application.yml
│   └── test/
│       └── java/com/bank/peak/
│           └── PeakPriceServiceTest.java

How do you build and run?

BASH
# Build
mvn clean package -DskipTests

# Run
java -jar target/peak-price-service-1.0.0.jar

# See convergence at FINE level
java -Djava.util.logging.ConsoleHandler.level=FINE \
  -jar target/peak-price-service-1.0.0.jar

What is the step-by-step walkthrough?

Input: prices 101, 108, 121, 140, 135, 119, 104.

Step 1: start is 0, end is 6, mid is 3, price at 3 is 140 and at 4 is 135; since 140 is greater, we are falling, so end becomes 3.
Step 2: start is 0, end is 3, mid is 1, price at 1 is 108 and at 2 is 121; since 108 is less, we are rising, so start becomes 2.
Step 3: start is 2, end is 3, mid is 2, price at 2 is 121 and at 3 is 140; since 121 is less, rising, so start becomes 3.
Step 4: start equals end at index 3, the loop ends, and the peak is price at 3, which is 140, the daily high.
CODE
Oct 27, 2026 9:58:13 PM com.bank.peak.service.PeakPriceService dailyHigh
INFO: Daily high at index 3 = 140
INFO: Rajesh SAV2001 stock daily high: 140

What is the high-level design?

DIAGRAM
  ═══ HLD — Intraday Daily-High Analytics (Banking) ═══

  ┌────────────┐ HTTPS ┌──────────────┐ REST ┌─────────────────────┐
  │ Analytics  │──────→│ API Gateway  │─────→│ Peak Price Svc ×2   │
  └────────────┘       │ (JWT, rate)  │      │ (Spring Boot)       │
                       └──────────────┘      └─────────┬───────────┘
                                                      │ load tick series
                                                      ▼
                                           ┌─────────────────────┐
                                           │ Time-series store    │
                                           └─────────────────────┘

What is the low-level design?

DIAGRAM
  ═══ LLD — Bitonic Array Maximum ═══

  ┌─ Design Patterns Used ──────────────────────────────────┐
  │  Binary search on slope via right-neighbour comparison   │
  │     WHY: slope sign pinpoints which half holds the peak  │
  └──────────────────────────────────────────────────────────┘

  ┌─ SOLID Principles Applied ──────────────────────────────┐
  │  S: service only finds the peak                          │
  │  O: any bitonic series works unchanged                   │
  │  D: depends only on primitive int array                  │
  └──────────────────────────────────────────────────────────┘

  ── Class Diagram ──────────────────────────────────────────
  ┌──────────────────────────────────────┐
  │ PeakPriceService                      │
  │ ───────────────────────────────────── │
  │ + dailyHigh(prices): int              │
  └──────────────────────────────────────┘

  ── State: [start,end] converge (start < end) ─────────────
  slope at mid decides which side to keep

  Contract for dailyHigh(prices):
    Pre:  prices strictly rise then strictly fall
    Post: the single maximum value

What is the time and space complexity?

Analyze the solution based on the algorithm used. Consider both the time to process input and the space required for any data structures.

What are common mistakes?

Common mistakes include off-by-one errors, not handling edge cases like empty input, and not considering the constraints of the problem.

What are the edge cases?

Edge cases include empty input, single element input, all identical elements, and boundary values.

What should a senior engineer know?

A senior engineer should understand the time-space tradeoffs, be able to explain the algorithm clearly, and know when this technique applies versus alternatives.

Visual Overview

DIAGRAM
  prices:[101,108,121,140,135,119,104]
    │
    ▼
  compare prices[mid] vs prices[mid+1]
    ├─ mid > mid+1 (falling) → end = mid
    └─ mid < mid+1 (rising)  → start = mid+1
    ▼
  start==end → peak index 3 → 140

Key Takeaway

Bitonic Array Maximum finds the single peak of an array that strictly rises and then strictly falls. I binary-search, but instead of comparing against a target I compare the middle element with its right neighbour. If the middle is larger than its right neighbour I am standing on the falling side, so the peak is at the middle or to its left and I move the end pointer to the middle. If the middle is smaller than its right neighbour I am on the rising side, so the peak is further right and I move the start pointer past the middle.

I use a start-less-than-end loop because I am converging two pointers onto one index rather than hunting for an exact value, and because the middle is always strictly below the end in that condition, reading the right neighbour never goes out of bounds. When the pointers meet, that single index is the peak.

At the National Bank of India I used this to compute the daily high of Rajesh's stock from a day's intraday prices stored as a bitonic series that climbs to the high and then declines. Rather than scanning thousands of ticks, I binary-searched on the slope by comparing each middle tick with its neighbour, landing on the high in logarithmic time, and this peak index also became the pivot for the related problem of searching a bitonic array. Explaining the slope comparison and the strict single-peak assumption is what shows an interviewer I understand why the neighbour test is decisive.

Remember one sentence: understand the core algorithm and apply it to banking domain problems.

---

Share
Use ← → arrow keys to navigate