← Hudson River Trading Interview Insights

Hudson River Trading·Software Engineer·Technical Phone Screen·Intermediate

IntermediatePrefer not to say
Jun 2026

Summary

Interviewed for a software engineering role at Hudson River Trading and got a local minimum problem that started simple enough but kept expanding. The 2D follow-up is where things got interesting.

Questions Asked (5)

Q1

Given an array of unique integers, find any element that is smaller than both of its neighbors.

Algorithms & Data Structures
Author's notes

I jumped straight to a linear scan and it worked, but then they asked if O(log n) was expected and I kind of froze.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Clarify the problem constraints (e.g., array size, whether the array is circular, and if multiple valid answers exist). Then propose an efficient algorithm, such as binary search on the slope, which finds a local minimum in O(log n) time. Explain the intuition and handle edge cases like arrays of length 1 or 2.

Pro tip: Mention that this is a classic local minimum problem and that binary search works because any array must have at least one local minimum. Emphasize that you can return any such element, so you can guide the search based on the slope.

1. Clarify the problem

Ask about array size, uniqueness, circularity, and whether multiple answers are acceptable. Confirm that a local minimum is defined as an element smaller than both neighbors.

2. Discuss brute force and its complexity

Mention that a linear scan checking each element takes O(n) time. This shows you understand the baseline and can optimize.

3. Propose binary search approach

Explain that you can use binary search by comparing the middle element with its neighbors. If it's a local minimum, return it; otherwise, move towards the smaller neighbor.

4. Walk through an example

Trace the algorithm on a sample array to demonstrate correctness and how the search space halves each step.

5. Analyze complexity and edge cases

State that the time complexity is O(log n) and space is O(1). Discuss edge cases like arrays of length 1 or 2, and how to handle boundaries.

Key Points to Mention

  • Definition of local minimum: element smaller than both neighbors.
  • Binary search works because the array has a 'valley' somewhere.
  • Comparison with neighbors to decide direction: if left neighbor is smaller, go left; if right neighbor is smaller, go right.
  • Time complexity O(log n) and space O(1).
  • Edge cases: length 1 (return the only element), length 2 (return the smaller one).
  • Uniqueness of elements ensures no equal neighbors, simplifying comparisons.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Extend the local minimum problem to a 2D matrix where a cell must be smaller than all four of its adjacent neighbors (up, down, left, right).

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

This one tripped me up more than I expected.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the problem: define what constitutes a local minimum in a 2D matrix and discuss edge cases. Then present a divide-and-conquer approach that finds a local minimum in O(n) time for an n x n matrix, explaining the algorithm step-by-step. Finally, analyze the time and space complexity and compare with naive approaches.

Pro tip: Mention that the divide-and-conquer approach can be extended to find a local minimum in O(n) time, which is optimal, and highlight that this problem tests your ability to optimize beyond brute force.

1. Clarify the problem and edge cases

Define a local minimum as a cell smaller than its four orthogonal neighbors. Discuss boundary conditions (edges and corners have fewer neighbors) and whether the matrix can have duplicates or negative numbers.

2. Discuss brute force and its limitations

A naive approach scans all cells and checks neighbors, taking O(n^2) time for an n x n matrix. Explain why this is inefficient for large matrices.

3. Present the divide-and-conquer algorithm

Find the minimum value in the middle column, check its left and right neighbors. If it's smaller than both, it's a local minimum. Otherwise, recurse on the half that contains the smaller neighbor. This reduces the search space by half each time.

4. Analyze time and space complexity

The algorithm examines O(n) elements per column and halves the columns each step, leading to O(n) total time. Space complexity is O(log n) due to recursion, or O(1) if implemented iteratively.

5. Discuss trade-offs and extensions

Compare with other approaches (e.g., greedy walk) and mention that the divide-and-conquer guarantees finding a local minimum in O(n) time. Also, note that the problem can be extended to higher dimensions or with different neighbor definitions.

Key Points to Mention

  • Definition of local minimum in 2D: smaller than all four adjacent neighbors (up, down, left, right).
  • Edge cases: boundaries and corners have fewer neighbors; duplicates may exist.
  • Brute force O(n^2) vs. divide-and-conquer O(n) time complexity.
  • Divide-and-conquer steps: find min in middle column, compare with horizontal neighbors, recurse on the side with the smaller neighbor.
  • Proof of correctness: the algorithm always finds a local minimum because the smaller neighbor leads to a descending path.
  • Space complexity: O(log n) for recursive, O(1) for iterative; time complexity O(n) for n x n matrix.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

How would the solution change if duplicate values were allowed in the array or matrix?

Algorithms & Data Structures
Author's notes

Didn't have a clean answer.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the original problem and the specific algorithm being used, then systematically analyze how duplicates affect each step, focusing on correctness, edge cases, and complexity. Propose modifications such as adjusting comparisons, using additional data structures, or changing traversal logic to handle duplicates without breaking invariants.

Pro tip: Demonstrate awareness that duplicates often require rethinking assumptions about uniqueness, and mention that in trading systems, handling duplicates correctly is crucial for data integrity and performance.

1. Clarify the original problem and solution

Restate the problem and outline the current algorithm, including its assumptions about uniqueness and how it uses comparisons or indexing.

2. Identify impacted components

Determine which parts of the algorithm rely on uniqueness, such as binary search conditions, hash-based lookups, or sorted order assumptions.

3. Analyze correctness and edge cases

Consider scenarios where duplicates cause incorrect results, infinite loops, or missed elements, and identify necessary condition changes.

4. Propose modifications

Suggest concrete changes, like using <= instead of <, adding tie-breaking logic, or employing auxiliary structures to track duplicates.

5. Evaluate complexity and trade-offs

Discuss how the modifications affect time and space complexity, and whether alternative approaches might be more suitable.

Key Points to Mention

  • Impact on search algorithms: binary search may need to find first/last occurrence instead of any match.
  • Hash-based solutions: duplicates may cause collisions or require counting frequencies.
  • Sorting: stability and comparison functions may need adjustment to handle equal elements.
  • Dynamic programming: state transitions may need to account for multiple identical values.
  • Graph algorithms: duplicate edges or nodes can affect traversal and cycle detection.
  • Complexity changes: additional passes or data structures may increase time/space complexity.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Can you find all local minima instead of just one, and what's the complexity?

Algorithms & Data Structures
Author's notes

Short answer: linear scan, O(n).

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the problem: whether the array is unimodal or arbitrary, and whether local minima are defined strictly or non-strictly. Then, discuss that finding all local minima in an arbitrary array requires O(n) time in the worst case, but if the array is unimodal, you can find the single minimum in O(log n) and all minima are just that one. For multiple local minima in an arbitrary array, a linear scan is optimal, but you can optimize by skipping elements when possible.

Pro tip: Mention that in a rotated sorted array, there is exactly one local minimum, which can be found in O(log n) using binary search, but if the array has multiple local minima, binary search doesn't directly apply. Also, note that the number of local minima can be up to n/2, so any algorithm must at least read the input, making O(n) optimal.

1. Clarify the problem

Ask whether the array is unimodal, rotated sorted, or arbitrary, and whether local minima are strict (a[i] < a[i-1] and a[i] < a[i+1]) or non-strict. Also confirm if the array has distinct elements.

2. Identify the appropriate algorithm

For an arbitrary array, a linear scan is optimal. For a unimodal or rotated sorted array, binary search can find the single minimum in O(log n). If multiple minima are possible, explain that binary search doesn't work directly.

3. Analyze complexity

State that finding all local minima in an arbitrary array requires Ω(n) time because you must examine each element at least once in the worst case. The space complexity is O(1) if you only output indices, or O(k) if you store them.

4. Discuss optimizations and edge cases

Mention that you can skip elements if you know the array is sorted or has structure, but for general arrays, linear scan is optimal. Handle edge cases like empty array, single element, and plateaus (equal adjacent elements).

5. Provide code or pseudocode

Outline a simple linear scan that checks each element (except boundaries) and collects local minima. If the array is unimodal, describe binary search to find the single minimum.

Key Points to Mention

  • Definition of local minimum: a[i] < a[i-1] and a[i] < a[i+1] (or <= for non-strict).
  • Worst-case time complexity: O(n) for arbitrary arrays, and this is optimal because you must read all elements.
  • Binary search works for unimodal arrays to find the single minimum in O(log n).
  • Number of local minima can be up to n/2, so output size can be O(n).
  • Edge cases: empty array, single element, boundaries, and plateaus.
  • Space complexity: O(1) extra space if only counting, O(k) if storing indices.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

What changes if diagonal neighbors also count as adjacent in the 2D version?

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

I said the divide and conquer approach gets messier because your guarantees about which half to recurse into depend on only having 4-directional adjacency.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First clarify the problem context (e.g., grid traversal, connected components, shortest path) and then systematically analyze how adding diagonal adjacency changes the graph structure, algorithmic choices, and complexity. Discuss specific impacts on common algorithms like BFS/DFS, Dijkstra, and A*, and mention trade-offs such as increased branching factor and potential for diagonal shortcuts.

Pro tip: Explicitly state whether diagonal moves are allowed to 'cut corners' between two orthogonally adjacent blocked cells; this subtlety often distinguishes a correct implementation from a buggy one and shows attention to real-world constraints.

1. Clarify the problem context

Identify the specific 2D problem (e.g., grid pathfinding, connected components, flood fill) and the current adjacency definition (4-directional). Confirm whether diagonal moves are allowed to pass between two blocked orthogonal neighbors.

2. Analyze graph structure changes

Explain that each cell now has up to 8 neighbors instead of 4, increasing the branching factor. This affects traversal order, memory usage, and the number of edges in the graph.

3. Assess algorithmic impact

Discuss how BFS/DFS will explore more nodes per step, potentially finding shorter paths (in terms of steps) but with different geometric distances. For weighted grids, Dijkstra/A* may need adjusted heuristics (e.g., octile distance).

4. Consider complexity and trade-offs

Note that time and space complexity can increase (e.g., O(8^d) vs O(4^d) for naive DFS), but diagonal moves can reduce path length. Mention potential issues like diagonal shortcuts through walls and the need for corner-cutting rules.

5. Summarize implications and edge cases

Conclude with practical implications: better path quality in open grids, but risk of unnatural paths or invalid moves if corner-cutting is allowed. Highlight edge cases like narrow corridors and isolated cells.

Key Points to Mention

  • Branching factor increases from 4 to 8, affecting traversal and search algorithms.
  • BFS/DFS may find paths with fewer steps but different geometric lengths; shortest path in steps may not be Euclidean shortest.
  • Heuristics for A* must change (e.g., from Manhattan to Chebyshev or octile distance).
  • Corner-cutting: whether diagonal moves can pass between two orthogonally adjacent blocked cells.
  • Complexity implications: more edges in the graph, potential for faster goal reach but higher per-node expansion cost.
  • Real-world applications: grid-based games, robotics path planning, and image processing where 8-connectivity is common.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.