Back to Stream Practice: Employee Analysis
Q42Question 42 of 43

Find the Nth-highest salary (make it generic for any N)

Key Concepts
  • map(getSalary).distinct().sorted(reverseOrder()).skip(n-1).findFirst() is the generic Nth-highest pattern
  • distinct() ensures duplicate salary amounts count as one position
  • If n exceeds the number of distinct salaries, findFirst returns Optional.empty()
  • Validate that n >= 1; throw IllegalArgumentException for invalid input
  • The same pattern works for Nth-lowest by using naturalOrder() instead of reverseOrder()
  • For Nth-highest per department, apply the pattern within each group after groupingBy

Definition

Map to salary, distinct to collapse duplicates, sort descending, skip(n-1), and findFirst to get the Nth-highest unique salary.
  • Pattern: map(getSalary).distinct().sorted(reverseOrder()).skip(n-1).findFirst()
  • distinct() ensures two employees earning the same amount count as one rank position.
  • skip(n-1) passes over the first n-1 unique salary values.
  • findFirst() returns Optional for the Nth position.
  • Empty result when n exceeds the number of distinct salaries.

The bank's salary committee asks: 'What is the 5th-highest distinct salary in the organization?' Line up all unique salary amounts from highest to lowest, count to the 5th one, and report it.

Understanding the Concepts

What does this question ask?

Generalize the second-highest salary pattern to any N. This tests parameterization and edge case handling.

How do you find the Nth-highest salary?

JAVA
package com.bank.hr;

import java.math.BigDecimal;
import java.util.*;

public class NthHighestSalary {
    public static Optional<BigDecimal> findNthHighest(
            List<Employee> employees, int n) {
        if (n < 1) throw new IllegalArgumentException(
            "N must be >= 1, got: " + n);

        return employees.stream()
            .map(Employee::getSalary)
            .distinct()
            .sorted(Comparator.reverseOrder())
            .skip(n - 1)
            .findFirst();
    }

    public static void main(String[] args) {
        List<Employee> employees = Employee.getSampleEmployees();

        for (int n = 1; n <= 5; n++) {
            Optional<BigDecimal> salary = findNthHighest(employees, n);
            System.out.printf("Position %d: %s%n", n,
                salary.map(s -> "Rs." + s).orElse("N/A"));
        }
    }
}
TEXT
Position 1: Rs.1800000
Position 2: Rs.1500000
Position 3: Rs.1400000
Position 4: Rs.1300000
Position 5: Rs.1200000

How do you find the Nth-lowest?

JAVA
Optional<BigDecimal> nthLowest = employees.stream()
    .map(Employee::getSalary)
    .distinct()
    .sorted(Comparator.naturalOrder())  // ascending
    .skip(n - 1)
    .findFirst();

What about edge cases?

JAVA
// N exceeds distinct salaries: returns empty
Optional<BigDecimal> empty = findNthHighest(employees, 100);
System.out.println(empty.isPresent());  // false

// N = 1: returns the highest salary
Optional<BigDecimal> highest = findNthHighest(employees, 1);

// Single employee: only N=1 returns a value
List<Employee> single = List.of(new Employee("E001", "Rajesh",
    "TRADING", new BigDecimal("1800000")));
Optional<BigDecimal> pos2 = findNthHighest(single, 2);  // empty

What are common mistakes?

Mistake: using skip(n) instead of skip(n-1).

JAVA
// WRONG: skip(n) skips n elements, giving position n+1
Optional<BigDecimal> wrong = employees.stream()
    .map(Employee::getSalary).distinct()
    .sorted(Comparator.reverseOrder())
    .skip(3)      // skips positions 1, 2, 3
    .findFirst(); // returns position 4, not 3!

// CORRECT: skip(n-1) for position n
Optional<BigDecimal> correct = employees.stream()
    .map(Employee::getSalary).distinct()
    .sorted(Comparator.reverseOrder())
    .skip(2)      // skips positions 1, 2
    .findFirst(); // returns position 3

What about the time and space complexity?

| Operation | Complexity |
|---|---|
| map(getSalary) | O(n) |
| distinct() | O(n) with HashSet |
| sorted() | O(d log d) where d = distinct salaries |
| skip + findFirst | O(1) |
| Total | O(n + d log d) |

What are common interview follow-up questions?

  • "How do you return the employees at that salary?" Find the Nth salary first, then filter all employees matching it.
  • "What is the time complexity?" O(n log n) for the sort.
  • "How do you find Nth-highest per department?" Group first, then apply the pattern within each group.

Visual Overview

DIAGRAM
  findNthHighest(employees, 3):

  map(getSalary) → [1800K, 1000K, 1400K, 1200K, 1800K, ...]
       │
  distinct() → [1800K, 1000K, 1400K, 1200K, 1500K, ...]
       │
  sorted(desc) → [1800K, 1500K, 1400K, 1300K, 1200K, ...]
       │
  skip(2) → [1400K, 1300K, 1200K, ...]
       │
  findFirst() → Optional[1400K]  ← 3rd-highest

Key Takeaway

The Nth-highest salary pattern generalizes to any N: map(getSalary).distinct().sorted(reverseOrder()).skip(n-1).findFirst(). The distinct step ensures duplicate amounts count as one position. Validate that N is at least 1 and handle the empty case when N exceeds the number of distinct salaries.

Remember one sentence: distinct-sort-skip(n-1)-findFirst is the generic Nth-highest pattern, and it returns empty when N exceeds the number of distinct values.

---

Share
Use ← → arrow keys to navigate