Wells Fargo Interview Questions · 2026

Wells Fargo Interview Questions (2026): With Answers

A candidate who sat for Wells Fargo's on-campus drive in September 2025 described a first-round aptitude test with a 10-minute "fitness section" built around a Floyd-Warshall shortest-path problem, buried in among verbal ability and data interpretation questions that had nothing to do with graphs. That's the pattern that shows up across dozens of reported loops: Wells Fargo mixes a genuinely broad, sometimes odd, assessment with a technical loop that's much more conventional once you're through the door. Glassdoor's aggregate for the Software Engineer track lists a three-round shape, an initial HackerRank screen, a live coding round with two problems worked on a call, and a managerial round about past projects, and rates candidate experience as roughly 53 percent positive with an average difficulty of 2.8 out of 5 (Glassdoor, Wells Fargo Software Engineer interviews).

What's consistent across engineering, data, and analyst tracks is that Wells Fargo doesn't lean hard on obscure algorithm trivia. Coding rounds run leetcode-easy to leetcode-medium, and the follow-up questions are usually about tradeoffs in your own project, not a rehearsed whiteboard pattern. Core Java, REST versus SOAP, collections internals, and basic system design show up constantly for engineering roles, while data and analytics candidates get pulled into SQL window functions and loan or transaction aggregation queries that map directly to what the bank actually does with customer data. The HR and values round at the end asks about the bank's core values almost verbatim, which is unusual enough that it's worth preparing for on its own terms rather than treating it as generic behavioral filler.

This page groups roughly 50 questions into seven rounds that mirror what candidates actually report, from the online assessment through the final HR conversation. Coding examples use Java where that's the reported language of choice, since it's the one most frequently named across engineering interview write-ups.

51Questions
5-6Rounds
HackerRankOA Format
53%Positive Experience

Round 1: Online assessment (HackerRank / aptitude)

Reports describe a mixed test, two programming problems plus four or five objective questions on quantitative reasoning, verbal ability, and basic CS. It's timed tightly enough that panicking on the reasoning section costs you time you need for the coding half.

Easy questions

16

Reports consistently describe string manipulation, checking for primes, finding duplicates in an array, generating a Fibonacci sequence, and counting vowels or characters in a string. None of it is exotic. The bar is writing correct, clean code quickly, not clever code.

The objective questions alongside the coding problems tend to cover basic data structures, a bit of DBMS, and general aptitude. Treat the whole thing as a speed and accuracy test rather than a depth test, since the interviewers you'll meet later are the ones who actually probe depth.

The naive approach checks every divisor up to n minus one. The first real improvement is checking only up to the square root of n, since any factor larger than the square root would have a matching factor smaller than it that you'd have already found.

java
boolean isPrime(long n) {
  if (n < 2) return false;
  if (n % 2 == 0) return n == 2;
  for (long i = 3; i * i <= n; i += 2) {
    if (n % i == 0) return false;
  }
  return true;
}

Skipping even numbers after checking 2 separately cuts the loop roughly in half again. For genuinely huge numbers you'd move to a probabilistic test like Miller-Rabin, but nobody expects that in a timed OA, the square-root loop is the answer they want to see.

A hash set gives you a single pass: iterate the array, and for each element check whether it's already in the set. If it is, it's a duplicate; if not, add it. That's O(n) time and O(n) space.

java
List<Integer> findDuplicates(int[] arr) {
  Set<Integer> seen = new HashSet<>();
  List<Integer> dupes = new ArrayList<>();
  for (int x : arr) {
    if (!seen.add(x)) {
      dupes.add(x);
    }
  }
  return dupes;
}

If the interviewer adds a constraint that you can't use extra space, and the array's values are bounded between 1 and n, you can sort in place or negate values at the index each value points to, trading a cleaner constant factor for a harder-to-read solution. I'd only reach for that trick if asked directly about the space constraint.

The coding problems carry more weight and are harder to partially credit than multiple choice questions, where a wrong guess costs you the same as leaving it blank in most scoring systems. I'd read both coding problems first, bank the one that looks faster to finish correctly, then use whatever time is left on the objective section rather than the reverse.

Candidates who report struggling with this round usually say they burned ten minutes on a tricky reasoning question early and then rushed the second coding problem. Triage the paper the way you'd triage a real backlog, cheapest wins first.

Naive recursion, fib(n) = fib(n-1) + fib(n-2), recomputes the same subproblems exponentially many times, O(2^n) in the worst case, because it has no memory of what it already calculated.

java
int[] fibonacci(int n) {
  int[] result = new int[n];
  if (n > 0) result[0] = 0;
  if (n > 1) result[1] = 1;
  for (int i = 2; i < n; i++) {
    result[i] = result[i - 1] + result[i - 2];
  }
  return result;
}

Building it iteratively from the bottom up is O(n) time and needs only the last two values in memory if you don't need the full array back, which is the detail that shows you understand why the naive version was slow in the first place, not just that a faster version exists.

Brute force checks every pair, O(n squared). A hash map gets it down to O(n): for each number, check whether target minus that number is already in the map before adding the current number.

java
int[] twoSum(int[] nums, int target) {
  Map<Integer, Integer> seen = new HashMap<>();
  for (int i = 0; i < nums.length; i++) {
    int complement = target - nums[i];
    if (seen.containsKey(complement)) {
      return new int[]{seen.get(complement), i};
    }
    seen.put(nums[i], i);
  }
  throw new IllegalArgumentException("No solution");
}

It's a warm-up question in most loops, but interviewers still watch for whether you check the complement before inserting the current value, doing it the other way around lets you match an element with itself when the array has a duplicate at index zero.

Iteratively: walk the list keeping track of the previous node, and at each step flip the current node's next pointer to point backward before advancing both pointers.

java
ListNode reverseList(ListNode head) {
  ListNode prev = null, curr = head;
  while (curr != null) {
    ListNode next = curr.next;
    curr.next = prev;
    prev = curr;
    curr = next;
  }
  return prev;
}

The recursive version is a few lines shorter but adds O(n) call stack depth, which is a real risk on a genuinely long list, a large linked structure loaded from a database, say, where you could hit a stack overflow that the iterative version would never risk. I'd use the iterative version in anything production, and only reach for the recursive one in a coding exercise where clarity of the recursive structure is the actual point.

If the strings are ASCII, a fixed-size count array beats a hash map on constant factor. Increment counts for characters in the first string, decrement for the second, and check every count is zero at the end.

java
boolean isAnagram(String s, String t) {
  if (s.length() != t.length()) return false;
  int[] counts = new int[26];
  for (char c : s.toCharArray()) counts[c - 'a']++;
  for (char c : t.toCharArray()) counts[c - 'a']--;
  for (int c : counts) if (c != 0) return false;
  return true;
}

ArrayList is backed by a resizable array, so random access by index is O(1) but inserting or removing from the middle means shifting every element after it, O(n). LinkedList is a doubly linked structure, so insertion and removal at a known node are O(1), but getting to that node by index means walking the list, also O(n).

The place this actually bites people is a hot loop that does list.get(i) against a LinkedList inside a for loop, which turns an O(n) traversal into an accidental O(n squared) because every get call walks from one end. I've seen that exact bug in a real codebase; the fix was just switching the backing type, no algorithm change needed.

REST is an architectural style built on HTTP verbs and typically JSON, stateless, and lightweight. SOAP is a strict messaging protocol with an XML envelope, a formal contract (WSDL), and built-in extensions for things like transactional reliability and message-level security.

I'd genuinely reach for SOAP today only when integrating with a legacy enterprise system, an older core banking platform, say, that only speaks SOAP and where the formal contract and built-in reliability guarantees are worth the verbosity. For anything greenfield, REST or gRPC wins on developer speed and tooling almost every time. At a bank the honest answer is that both exist in production simultaneously, and knowing when you're stuck maintaining the SOAP side matters as much as preferring REST for new work.

A CDN caches content at edge locations physically closer to users, cutting latency and load on the origin server for content that's the same for everyone, static assets, images, JS bundles.

For a banking application, most of the interesting data (account balances, transaction history) is personalized per user and can't be cached at the edge the same way. A CDN still earns its keep for the static shell of the app, everything before the personalized data loads, but the honest answer is that it solves a smaller fraction of the real performance problem than it does for a content site. That distinction is usually what the interviewer is actually listening for.

An AVG on the balance column grouped by customer, but the join matters more than the aggregation here. An inner join between customers and a balances table silently drops customers with no rows in balances, which is a real bug if the business question is "average balance across all customers," not just the ones with recorded activity.

sql
SELECT c.customer_id, COALESCE(AVG(b.balance), 0) AS avg_balance
FROM customers c
LEFT JOIN balances b ON c.customer_id = b.customer_id
GROUP BY c.customer_id;

LEFT JOIN plus COALESCE keeps every customer in the result and reports zero instead of silently dropping them, which is the difference between an answer that's technically correct for the wrong population and one that's actually correct for the question being asked.

Reports describe this question paired with a check on whether you're aware of competing offers or competitor banks, so a generic "I want to work at a big bank" answer reads as unprepared. I'd reference something specific and current, the bank's ongoing technology modernization push, or a specific business line relevant to the role you're interviewing for, rather than reciting the mission statement back.

The stronger move is connecting your own background to a specific team or problem the role actually touches, which also signals you read the job description carefully rather than applying broadly without much thought.

The honest version of this answer, even if the origin story is mundane, reads better than a polished one that sounds rehearsed. I'd connect a specific class, project, or early job experience to the actual work of the role you're applying for, rather than a generic "I've always loved technology" line that could apply to any candidate for any job.

The useful structure here is one sentence per role on what you were hired to do, one sentence on what you actually accomplished, and one honest sentence on why you left. Skipping the "why you left" part or being vague about it is the thing that makes an interviewer probe harder, not less.

Always yes, and the questions worth asking at this stage are about team structure, what a first ninety days looks like, or what's changed recently on the team, not questions you could have answered by reading the job posting. I'd ask at least one question specific to something the interviewer said earlier in the conversation, which also shows you were actually listening, not just running through a memorized list.

Medium questions

24

The tell is usually a small, dense grid or matrix of pairwise distances or costs between nodes, with a question asking for the cheapest way to get from every node to every other node, not just one pair. That "all pairs" framing is the signal to reach for Floyd-Warshall instead of a single-source algorithm like Dijkstra.

java
int[][] floydWarshall(int[][] dist, int n) {
  for (int k = 0; k < n; k++) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        if (dist[i][k] + dist[k][j] < dist[i][j]) {
          dist[i][j] = dist[i][k] + dist[k][j];
        }
      }
    }
  }
  return dist;
}

It's O(n cubed), which is fine for the small grids these puzzles use, and the whole algorithm is short enough to type from memory under time pressure if you've seen it once before. That's really what the round is testing, pattern recognition under a clock, not derivation from scratch.

A max-heap built from the whole array, then popping k minus one times, gets you the answer in O(n + k log n), and it's the approach most candidates reach for first because it's easy to reason about correctly under pressure.

java
int findKthLargest(int[] nums, int k) {
  PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
  for (int n : nums) maxHeap.add(n);
  for (int i = 0; i < k - 1; i++) maxHeap.poll();
  return maxHeap.peek();
}

Quickselect, a variant of quicksort's partition step that only recurses into the half containing the kth index, averages O(n) time, which is genuinely faster, but it has a worst-case O(n squared) if pivots are chosen badly and it's noticeably harder to get exactly right live on a call. I'd lead with the heap solution, then mention quickselect as the follow-up optimization if the interviewer pushes on time complexity.

A sliding window with a hash map tracking the last seen index of each character gets this in O(n). Move the right pointer forward one character at a time; if that character was seen inside the current window, jump the left pointer past its previous occurrence instead of stepping it one at a time.

java
int lengthOfLongestSubstring(String s) {
  Map<Character, Integer> lastSeen = new HashMap<>();
  int maxLen = 0, left = 0;
  for (int right = 0; right < s.length(); right++) {
    char c = s.charAt(right);
    if (lastSeen.containsKey(c) && lastSeen.get(c) >= left) {
      left = lastSeen.get(c) + 1;
    }
    lastSeen.put(c, right);
    maxLen = Math.max(maxLen, right - left + 1);
  }
  return maxLen;
}

The jump-the-left-pointer detail is what separates a correct O(n) solution from an O(n squared) one that still passes small test cases but times out on a longer input.

Floyd's cycle detection, two pointers moving at different speeds. A slow pointer advances one node at a time, a fast pointer advances two. If there's a cycle, the fast pointer eventually laps the slow one and they meet inside the loop; if there's no cycle, the fast pointer hits null first.

java
boolean hasCycle(ListNode head) {
  ListNode slow = head, fast = head;
  while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
    if (slow == fast) return true;
  }
  return false;
}

The O(1) space is the whole point of the follow-up question, since a hash set of visited nodes solves the same problem trivially but costs O(n) memory, and interviewers usually ask for the space-optimal version specifically once you've shown the naive one works.

Breadth-first search with a queue. Process one full level at a time by capturing the queue's size before you start dequeuing, so you know exactly when one level ends and the next begins.

java
List<List<Integer>> levelOrder(TreeNode root) {
  List<List<Integer>> result = new ArrayList<>();
  if (root == null) return result;
  Queue<TreeNode> queue = new LinkedList<>();
  queue.add(root);
  while (!queue.isEmpty()) {
    int size = queue.size();
    List<Integer> level = new ArrayList<>();
    for (int i = 0; i < size; i++) {
      TreeNode node = queue.poll();
      level.add(node.val);
      if (node.left != null) queue.add(node.left);
      if (node.right != null) queue.add(node.right);
    }
    result.add(level);
  }
  return result;
}

Track the best sum ending at the current position, and reset it to the current element alone whenever the running sum would drag the total below just starting fresh here. A negative running total can never help a future subarray, so throwing it away is never a loss.

java
int maxSubArray(int[] nums) {
  int maxEndingHere = nums[0], maxSoFar = nums[0];
  for (int i = 1; i < nums.length; i++) {
    maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
    maxSoFar = Math.max(maxSoFar, maxEndingHere);
  }
  return maxSoFar;
}

The proof that the greedy choice is safe is worth stating out loud, that's usually what turns "I remembered the algorithm" into "I understand why it's correct" in the interviewer's notes.

If you have extra room at the end of the first array (a common variant of this question), walk both arrays from the back, comparing the largest remaining elements and placing the bigger one at the end of the merged space. Working from the back avoids overwriting values you haven't compared yet, which is the trap that going front-to-back in place falls into.

java
void merge(int[] nums1, int m, int[] nums2, int n) {
  int i = m - 1, j = n - 1, k = m + n - 1;
  while (j >= 0) {
    if (i >= 0 && nums1[i] > nums2[j]) {
      nums1[k--] = nums1[i--];
    } else {
      nums1[k--] = nums2[j--];
    }
  }
}

It breaks the contract every hash-based collection depends on: equal objects must produce equal hash codes. If you override equals to say two objects with the same id are equal, but leave the default hashCode (based on memory identity), those two logically-equal objects can land in different buckets of a HashMap or HashSet, and lookups that should find an existing entry will fail to.

java
class Account {
  String id;
  @Override
  public boolean equals(Object o) {
    return o instanceof Account && ((Account) o).id.equals(this.id);
  }
  // missing: hashCode override
}

Set<Account> seen = new HashSet<>();
seen.add(new Account("1001"));
seen.contains(new Account("1001")); // can return false, contract broken

This is a real bug pattern, not a trivia question, it shows up whenever someone adds an equals override for business logic reasons and forgets the hashCode has to move with it.

Checked exceptions, subclasses of Exception excluding RuntimeException, must either be caught or declared in the method signature with throws, and the compiler enforces it. Unchecked exceptions, subclasses of RuntimeException, need no such declaration and can propagate silently until something catches them or the program crashes.

My honest take: checked exceptions make sense for genuinely recoverable conditions the caller can reasonably act on, a file not found, a network timeout worth retrying. They get abused constantly for programmer errors, a null argument, an invalid index, that should be unchecked because there's no sane recovery path other than fixing the bug. A lot of the "checked exceptions are bad" opinion in the industry comes from codebases that used them for the wrong category of failure, not from a flaw in the mechanism itself.

The classic case is a chain of calls where an intermediate object, not the one you checked, is null. Checking if (user != null) and then calling user.getAddress().getCity() still throws if getAddress() itself returns null, since you only verified user, not the object user.getAddress() hands back.

java
if (user != null) {
  String city = user.getAddress().getCity();
  // still NPEs here if getAddress() returns null
}

The fix is either checking each link in the chain explicitly or using Optional to make the possibility of absence part of the type instead of an assumption you have to remember to verify at every level.

A process has its own isolated memory space, file handles, and resources; a thread shares memory and most resources with the other threads in its process but has its own stack and program counter. Threads are cheaper to create and communicate faster since they share memory directly, but that sharing is also where race conditions come from.

A context switch between processes has to swap the entire memory mapping, page tables, cache state, which is expensive. A context switch between threads in the same process only needs to save and restore the CPU registers and stack pointer, since the memory space doesn't change, which is why thread switches are meaningfully cheaper than process switches even though both interrupt whatever was running.

Relational when the data has clear relationships that need to stay consistent (an account, its owner, its transactions) and you need transactions and strong consistency across those relationships. NoSQL, document or key-value, when the access pattern is simple lookups by a known key at very high volume, and the schema is likely to evolve without a rigid relationship structure.

At a bank, core account and transaction data almost always lands on the relational side because ACID guarantees matter more than raw throughput. A session store, a cache layer, or an event log for audit trails are the places NoSQL or a specialized store earns its place instead. I'd resist a blanket "NoSQL scales better" answer, since a well-indexed relational database handles far more load than people assume before you actually need to shard.

A cache trades a small risk of staleness for a large reduction in database load and latency. The core tradeoff is choosing an invalidation strategy: write-through (update the cache and database together, safest but adds write latency), write-behind (update the cache first, database asynchronously, fastest but risks losing data on a crash), or a simple TTL that just accepts staleness up to a bounded window.

For financial data specifically, I'd lean toward short TTLs plus explicit invalidation on write, rather than trusting write-behind, since the cost of serving a stale balance to a user is much higher than the cost of a slightly slower write.

Sum the absolute value of each transaction (deposits, withdrawals, transfers, card purchases all count toward volume, not net movement), filter to the trailing 12 months, group by customer, and take the top 10 by that sum.

sql
SELECT customer_id, SUM(ABS(amount)) AS total_volume
FROM transactions
WHERE transaction_date >= CURRENT_DATE - INTERVAL '1 year'
GROUP BY customer_id
ORDER BY total_volume DESC
LIMIT 10;

The detail worth calling out unprompted: volume isn't the same as net balance change. A customer who deposits and withdraws the same amount repeatedly has high volume and zero net change, and the query needs ABS to capture that rather than letting deposits and withdrawals cancel out.

A window function with SUM and an ORDER BY inside the OVER clause. Ties on the same date need a deterministic tiebreaker, id, so the running total doesn't depend on arbitrary row order.

sql
SELECT
  customer_id,
  order_date,
  id,
  amount,
  SUM(amount) OVER (
    PARTITION BY customer_id
    ORDER BY order_date, id
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  ) AS running_total
FROM orders;

Without the explicit frame clause, some engines default to a range-based window that groups rows with equal order_date together for the running total instead of accumulating them one at a time, which silently produces a different, wrong answer for customers with same-day duplicate orders.

Filter to defaulted loans, extract the month from the default date, and aggregate with AVG, MAX, and MIN grouped by that month.

sql
SELECT
  DATE_TRUNC('month', default_date) AS default_month,
  AVG(loan_amount) AS avg_amount,
  MAX(loan_amount) AS max_amount,
  MIN(loan_amount) AS min_amount
FROM loans
WHERE status = 'DEFAULTED'
GROUP BY DATE_TRUNC('month', default_date)
ORDER BY default_month;

A clustered index determines the physical storage order of the table itself, there can only be one, usually the primary key. A non-clustered index is a separate structure that points back to the actual rows, and a table can have many of them.

For a transactions table, I'd cluster on something that matches the dominant query pattern, often (account_id, transaction_date) if most queries pull a customer's recent history, and add non-clustered indexes on columns used heavily in filters that don't match the clustering key, a status column used for fraud flags, say. Indexing everything defensively slows down every write, since each index has to be maintained on insert, so the answer has to weigh read pattern against write volume, not just "index the columns in the WHERE clause."

ETL transforms data before loading it into the destination warehouse, so the warehouse only ever holds clean, modeled data. ELT loads raw data first and transforms it inside the warehouse afterward, leaning on the warehouse's own compute for the transform step.

ELT has become the more common default as cloud warehouses got cheap enough to run heavy transforms directly, since it keeps raw data around for reprocessing if the transformation logic turns out to be wrong later, an ETL pipeline that dropped fields during the transform can't recover them without re-extracting from the source. I'd choose ETL specifically when the source system is fragile or rate-limited and you don't want to re-extract from it if a transform bug is found downstream.

I'd anchor this to a real production incident: a deploy that started throwing intermittent errors for a subset of users, with no clear root cause visible in the first ten minutes of logs. The decision was whether to roll back immediately, losing a feature customers were actively using, or hold and investigate for a few more minutes.

I chose to roll back. The reasoning I gave the team was that the cost of being wrong about "it'll resolve itself" was much higher than the cost of being wrong about "it needed more investigation," since a partial outage compounds the longer it runs. That's the actual point of this question at a bank specifically, not whether you can debug fast, but whether you default to the conservative choice when the downside is asymmetric.

The strongest version of this answer names a change that actually disrupted your plan, a reorg mid-project, a vendor dependency that got cut, a deadline moved up by weeks, rather than a minor scheduling adjustment. I'd walk through what specifically changed, what you had to deprioritize to absorb it, and what you'd do differently if it happened again.

What interviewers are actually screening for here is whether you treat a forced change as a problem to solve or a grievance to relitigate. The answer that lands is specific about the tradeoff you made, not just that you "stayed positive" through it.

This is the question that trips people up because it sounds like it requires insider knowledge of the company's exact value statements. It doesn't. I'd pick a value that's genuinely close to how you already work, ethical behavior, or risk awareness, and connect it to a concrete story: a time you flagged a shortcut a teammate proposed because it introduced risk the team hadn't priced in, for instance.

The failure mode to avoid is picking a value at random and forcing a story to fit it. Interviewers can tell the difference between a value you actually hold and one you memorized off the careers page an hour before the call.

I'd separate the two versions of this question. For a difficult teammate, the useful detail is what specifically made collaboration hard, missed handoffs, conflicting priorities, unclear ownership, and what concrete process change (not just "we talked it out") fixed it. For a difficult customer, banks in particular want to see that you de-escalate without simply agreeing to whatever the customer demands when it's not actually possible.

Either version works if you can name the specific friction and the specific fix. The generic "I listened and we found common ground" answer, without a concrete detail attached, is the version that doesn't land.

The useful version of this answer names the specific tradeoff you made to hit the deadline, cutting scope, working extra hours, pulling in help, and is honest about what you gave up to get there. A story where nothing had to be cut and everything worked out perfectly usually isn't believable, and interviewers notice when an answer is too clean.

I'd close with what you'd change about the planning that led to the crunch in the first place, since that shows you learned something structural, not just that you can grind through pressure once.

This lands better as a direction than a job title, moving toward deeper technical ownership, moving toward people management, moving into a specific domain like risk or fraud systems, rather than a specific title that assumes a promotion timeline the interviewer can't promise. I'd connect it back to something the role itself would actually build toward, which also signals you understood what the role does day to day.

Hard questions

7

Sort by start time first, that's the step candidates most often skip and then wonder why their merge logic breaks. Once sorted, walk the list and compare each interval's start against the end of the last merged interval; overlap means the current interval's start is less than or equal to that end.

java
int[][] merge(int[][] intervals) {
  Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
  List<int[]> merged = new ArrayList<>();
  for (int[] interval : intervals) {
    if (merged.isEmpty() || merged.get(merged.size() - 1)[1] < interval[0]) {
      merged.add(interval);
    } else {
      merged.get(merged.size() - 1)[1] =
        Math.max(merged.get(merged.size() - 1)[1], interval[1]);
    }
  }
  return merged.toArray(new int[merged.size()][]);
}

Sorting costs O(n log n), and the merge pass itself is O(n), so the whole thing is dominated by the sort. Interviewers asking this one at Wells Fargo often connect it afterward to a real scenario, merging overlapping transaction windows or account holds, so be ready to talk about why the same pattern applies there.

Start at the top-right corner. If the current value is bigger than the target, the entire column below it is also too big, so move left. If it's smaller, the entire row to the left is too small, so move down. Each step eliminates a full row or column, giving you O(m + n) instead of the O(m log n) you'd get from binary searching every row independently.

java
boolean searchMatrix(int[][] matrix, int target) {
  int row = 0, col = matrix[0].length - 1;
  while (row < matrix.length && col >= 0) {
    if (matrix[row][col] == target) return true;
    else if (matrix[row][col] > target) col--;
    else row++;
  }
  return false;
}

A deadlock is a cycle of threads or processes each holding a resource the next one in the cycle needs, so none of them can proceed. It requires four conditions simultaneously: mutual exclusion (resources can't be shared), hold and wait (a thread holds one resource while waiting for another), no preemption (resources can't be forcibly taken away), and circular wait (the chain of waiting forms a loop).

java
// classic two-lock deadlock
synchronized (lockA) {
  synchronized (lockB) { /* thread 1 */ }
}
// meanwhile, on another thread:
synchronized (lockB) {
  synchronized (lockA) { /* thread 2, opposite order */ }
}

Breaking any one of the four conditions prevents the deadlock. The practical fix in the example above is enforcing a consistent lock acquisition order everywhere in the codebase, which removes the circular wait condition without touching the other three.

A self-join or a window function comparing each customer's set of active months against the next one. The window approach avoids the combinatorial blowup a naive self-join can produce on a large transactions table.

sql
WITH monthly_activity AS (
  SELECT DISTINCT customer_id, DATE_TRUNC('month', transaction_date) AS active_month
  FROM transactions
)
SELECT a.customer_id, a.active_month
FROM monthly_activity a
LEFT JOIN monthly_activity b
  ON a.customer_id = b.customer_id
  AND b.active_month = a.active_month + INTERVAL '1 month'
WHERE b.active_month IS NULL;

EXPLAIN (or EXPLAIN ANALYZE, which actually runs the query and reports real timings) shows the sequence of operations the database planner chose, table scans versus index scans, join algorithms, and the estimated versus actual row counts at each step.

The most common finding on a slow report is a full table scan where an index scan was expected, usually because a function was applied to the indexed column in the WHERE clause, WHERE YEAR(transaction_date) = 2026 instead of a range comparison, which prevents the planner from using the index at all. The fix is almost always rewriting the predicate to be index-friendly rather than adding more indexes, since an index that can't be used because of how the query is written won't help no matter how many you add.

The honest structure here is: state the disagreement clearly and privately, make your case with specifics, and then commit fully once the decision is made, even if it doesn't go your way. I'd use a real example where I pushed back on a technical approach, lost the argument, and then describe specifically how I executed the decision I disagreed with rather than passively undermining it.

What separates a strong answer from a weak one isn't whether you won the disagreement. It's whether you can describe genuinely committing afterward, since a candidate who only tells "I was right and they eventually agreed" stories reads as someone who relitigates decisions rather than executing them.

This one maps directly onto risk management as a value, and it's worth having a real story ready rather than improvising. I'd pick an example where the risk wasn't obvious, a data migration that looked safe but had an edge case around a specific record type, a dependency version bump that quietly changed default behavior, and walk through how you found it and what you did once you had.

The part interviewers actually listen for is what you did after spotting the risk: did you raise it and get it fixed, or just note it and move on. A story that ends with "I flagged it and we caught it before it shipped" lands much better than one that ends with the risk simply being observed.

Real-time scenario questions

4

Each key's hashCode gets run through an internal hash spreading function, then reduced to an index into the backing array using a bitmask on the array length. Two keys that land on the same index form a collision, and Java resolves it by chaining, storing both entries in a linked list off that bucket.

java
Map<String, Integer> counts = new HashMap<>();
counts.put("wells", 1);
counts.put("fargo", 2);
// "wells" and "fargo" could hash to the same bucket index;
// both entries live in that bucket's linked list (or tree, if the bucket grows large)

Since Java 8, a bucket that grows past a threshold, eight entries, converts from a linked list to a red-black tree, turning worst-case lookup from O(n) down to O(log n) for that bucket. That detail specifically is what separates candidates who've read the JDK source once from candidates repeating a memorized definition.

The easy part is a table mapping a short code to a long URL and a redirect endpoint. The hard part is generating short codes at scale without collisions across many servers writing concurrently, and doing reads fast enough that the redirect doesn't add noticeable latency to every click.

For code generation, base-62 encoding a monotonically increasing counter (sharded per server, or handed out in blocks) avoids the coordination overhead of checking for collisions on every write. For reads, since redirects vastly outnumber writes, a cache in front of the database, keyed by short code, absorbs almost all the traffic and keeps the database mostly write-only. I'd bring up expiration and analytics tracking as the two features that usually get asked about right after the core design is settled.

A message queue, Kafka or similar, decouples ingestion from processing so a spike in incoming transactions doesn't fall over downstream consumers. Stream processing (something like Kafka Streams or Flink) does the real work, running aggregations and fraud-check rules against a sliding window of recent events, and writes results to a fast store, a key-value store or a time-series database depending on the query pattern.

At a bank specifically, the design has to account for exactly-once or at-least-once processing guarantees, since double-counting a transaction or silently dropping one has real financial consequences, not just a stale dashboard. I'd ask the interviewer directly which failure mode is worse for this use case before committing to a delivery guarantee, that question alone signals you've actually built something like this before.

The model needs a hold as its own row, not a mutation of the account's balance field directly, an account id, an amount, a reason code, a status (active, released, expired), and timestamps for created and released. Computing available balance becomes account balance minus the sum of active holds, calculated at read time rather than stored as a separate cached number that could drift out of sync.

java
class AccountHold {
  String holdId;
  String accountId;
  BigDecimal amount;
  String status; // ACTIVE, RELEASED, EXPIRED
  Instant createdAt;
  Instant expiresAt;
}
// available balance = account.balance - sum(holds where status = ACTIVE)

The interesting edge case interviewers push on is what happens when a hold expires exactly as a transaction is being processed against that balance, which is really a concurrency question wearing a domain-design costume. I'd answer with row-level locking or an optimistic version check on the account row during the balance calculation.

How to prepare for a Wells Fargo interview

Start with the OA, since it's the stage that eliminates the most candidates before a human ever reviews the file. Practice easy-to-medium problems on arrays, strings, and hashing under a real timer, not untimed, and don't skip basic graph algorithms like Floyd-Warshall just because they feel like a niche topic, they show up in the aptitude section specifically because most candidates haven't touched them since a data structures course.

For the technical loop, core Java depth (collections internals, equals and hashCode, checked versus unchecked exceptions) matters more than exotic algorithms, since the reported questions cluster there far more than around hard DSA. If you're going for a data or analytics role, spend real time on SQL window functions and joins against realistic, banking-shaped schemas, transactions, loans, holds, rather than abstract practice tables. For the values round, write down two or three specific stories in advance and map each one to a value the bank actually states, ethics, risk awareness, customer focus, rather than trying to improvise a fit in the moment.

Get the reps in before the real thing

Explaining an answer to yourself in the shower is not the same as defending it out loud when an interviewer asks a follow-up you didn't expect. LastRoundAI's mock interview mode runs live coding and behavioral rounds with real-time follow-up questions in your browser, and the free plan includes 15 credits a month that reset monthly rather than piling up unused.

Once your answers hold up under a follow-up, the slower part of the process is usually just getting in front of enough roles at banks and fintechs that actually run a loop like this one. Auto-Apply queues tailored applications for your review, 10 a month on the free plan, up to 400 a month on the Ultimate plan, and nothing goes out until you approve it.

Questions about either product go to contact@lastroundai.com.

How this list was built

Worth being straight about where these questions come from, because plenty of pages in this category are not. The set was compiled from a research pass across official documentation, vendor release notes, published engineering writing and public discussion of hiring processes, then cross-checked against the current version of each technology so nothing here describes behaviour that has since changed.

What that means in practice: these are the questions the material supports as reasonable and current for this role, not a transcript of any one company's loop. We have not sat in on your interview and we are not going to claim we have. Treat the list as well-sourced preparation rather than a leaked question bank, and expect your panel to phrase things their own way.

If you spot something out of date, tell us at contact@lastroundai.com and we will fix it.

Frequently asked questions

How technical is the Wells Fargo interview?

Technical enough that hand-waving fails. For engineering roles expect data structures, system design and questions about correctness under concurrency or scale. For analyst roles expect quantitative reasoning and comfort explaining a number you produced.

Does Wells Fargo ask brainteasers or probability questions?

Quantitative roles frequently do; general technology roles less often than their reputation suggests. If the role touches trading or research, probability and expected-value reasoning are fair game and worth rehearsing out loud.

What behavioural questions come up at Wells Fargo?

Ownership under pressure, handling a mistake with financial or client consequence, and working with people who disagree with you. Regulated environments care about judgement and escalation, so answers that show you knew when to raise something land well.

How should I prepare for the final round at Wells Fargo?

Know the business line you are joining, not just the firm. Candidates who can name what the desk or team actually does, and ask a specific question about it, separate themselves quickly at this stage.

Leave a Reply

Your email address will not be published. Required fields are marked *