Think youāre ready for a Microsoft technical interview? Try these 10 questions without looking at the solutions first.
Microsoft technical interviews are not simply about getting code to work. You may be expected to clarify the problem, discuss a brute-force approach, optimize it, explain your reasoning, write clean code, test edge cases, and defend your time and space complexity.
The complete Microsoft interview preparation guide takes that approach across 25 commonly reported Microsoft-style interview problems, covering arrays, strings, hashing, binary search, linked lists, trees, graphs, stacks, queues, recursion, and more.
Here are 10 problems from the preparation set with complete solutions.
1. Two Sum
The Question
Given an array of integers and a target, return the indices of two numbers that add up to the target.
Input:nums = [2, 7, 11, 15]target = 9Output:[0, 1]
The Idea
For every number, ask:
“What number do I need to reach the target?”
For 7 and target 9, we need 2.
A hash map lets us check whether that number has already appeared.
Solution
def two_sum(nums, target): seen = {} for index, num in enumerate(nums): needed = target - num if needed in seen: return [seen[needed], index] seen[num] = index return []
Why It Works
For every element:
š¬ Stay Ahead of Cyber Threats
Get the latest cybersecurity news, critical vulnerabilities, threat intelligence, tutorials, and exclusive giveaways delivered straight to your inbox. No spam. Unsubscribe anytime.
Subscribe to the Newsletter ā
needed = target - current
If needed is already in seen, we have found the pair.
Complexity
Time: O(n)Space: O(n)
The brute-force approach would use nested loops and take O(n²) time.
Typical follow-up: Can you solve it if the array is already sorted?
2. Maximum Subarray
The Question
Find the contiguous subarray with the largest sum.
Input:[-2, 1, -3, 4, -1, 2, 1, -5, 4]Output:6
The best subarray is:
[4, -1, 2, 1]
The Idea
At every number we have two choices:
- Continue the previous subarray.
- Start a new subarray here.
If the previous sum is hurting us, start fresh.
This is Kadane’s Algorithm.
Solution
def max_subarray(nums): current_sum = nums[0] best_sum = nums[0] for num in nums[1:]: current_sum = max(num, current_sum + num) best_sum = max(best_sum, current_sum) return best_sum
Example
For:
[-2, 1, -3, 4, -1, 2, 1]
the algorithm eventually discovers:
4 + (-1) + 2 + 1 = 6
Complexity
Time: O(n)Space: O(1)
Interview trap: Don’t initialize best_sum to 0. If every number is negative, the correct answer is the largest negative number.
3. Search in a Rotated Sorted Array
The Question
Search for a target in:
[4, 5, 6, 7, 0, 1, 2]
and return its index.
The expected solution for the standard distinct-element version is O(log n).
The Idea
Although the array is rotated, at least one half is still sorted.
For every iteration:
- Find the middle.
- Determine which half is sorted.
- Check whether the target belongs to that half.
- Eliminate the other half.
Solution
def search_rotated(nums, target): left = 0 right = len(nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] == target: return mid # Left half is sorted if nums[left] <= nums[mid]: if nums[left] <= target < nums[mid]: right = mid - 1 else: left = mid + 1 # Right half is sorted else: if nums[mid] < target <= nums[right]: left = mid + 1 else: right = mid - 1 return -1
Complexity
Time: O(log n)Space: O(1)
With duplicates, the worst case can degrade to O(n).
Typical follow-up: What changes when duplicate values are allowed?
4. Product of Array Except Self
The Question
Given:
[1, 2, 3, 4]
return:
[24, 12, 8, 6]
For every position, calculate the product of every other element.
The Catch
Don’t use division.
The Idea
For every position:
answer[i] =product on the leftĆproduct on the right
We can calculate both using prefix and suffix passes.
Solution
def product_except_self(nums): n = len(nums) result = [1] * n # Prefix products prefix = 1 for i in range(n): result[i] = prefix prefix *= nums[i] # Suffix products suffix = 1 for i in range(n - 1, -1, -1): result[i] *= suffix suffix *= nums[i] return result
Walkthrough
For:
[1, 2, 3, 4]
the prefix pass stores:
[1, 1, 2, 6]
The suffix pass then completes the answers:
[24, 12, 8, 6]
Complexity
Time: O(n)Space: O(1) extra space
The output array isn’t counted as extra space.
Typical follow-up: What happens when the input contains one or multiple zeroes?
5. Longest Substring Without Repeating Characters
The Question
Given:
"abcabcbb"
find the length of the longest substring containing no repeated characters.
Answer:
3
because:
"abc"
has length 3.
The Idea
Use a sliding window.
Think of two pointers:
left right ā ā [a b c a b c b b]
When a character repeats, move left forward.
Solution
def length_of_longest_substring(s): last_seen = {} left = 0 best = 0 for right, char in enumerate(s): if char in last_seen and last_seen[char] >= left: left = last_seen[char] + 1 last_seen[char] = right best = max(best, right - left + 1) return best
Complexity
Time: O(n)Space: O(min(n, alphabet_size))
The important detail is checking:
last_seen[char] >= left
Otherwise, you may accidentally move the window backward.
Typical follow-up: How would you modify the solution if the interviewer asked for the actual substring rather than just its length?
6. LRU Cache
This is where the interview starts testing more than basic algorithms.
The Question
Design a cache supporting:
get(key)put(key, value)
When the cache reaches capacity, remove the least recently used item.
The Key Insight
We need two things simultaneously:
Fast lookup
Hash Map
Fast insertion/removal/reordering
Doubly Linked List
Together:
Hash Map + Doubly Linked List
Solution
class Node: def __init__(self, key=0, value=0): self.key = key self.value = value self.prev = None self.next = Noneclass LRUCache: def __init__(self, capacity): self.capacity = capacity self.cache = {} self.head = Node() self.tail = Node() self.head.next = self.tail self.tail.prev = self.head def remove(self, node): node.prev.next = node.next node.next.prev = node.prev def add_to_end(self, node): last = self.tail.prev last.next = node node.prev = last node.next = self.tail self.tail.prev = node def get(self, key): if key not in self.cache: return -1 node = self.cache[key] self.remove(node) self.add_to_end(node) return node.value def put(self, key, value): if self.capacity <= 0: return if key in self.cache: self.remove(self.cache[key]) node = Node(key, value) self.cache[key] = node self.add_to_end(node) if len(self.cache) > self.capacity: lru = self.head.next self.remove(lru) del self.cache[lru.key]
Complexity
get(): O(1)put(): O(1)Space: O(capacity)
This is one of those problems where being able to explain why two data structures are needed is just as important as writing the implementation.
Typical follow-up: Can you implement it using Python’s OrderedDict?
7. Reverse a Linked List
The Question
Reverse:
1 ā 2 ā 3 ā 4 ā 5
into:
5 ā 4 ā 3 ā 2 ā 1
The Idea
At every node, change:
current.next
to point toward the previous node.
But before changing it, save the original next node.
Solution
def reverse_list(head): previous = None current = head while current: next_node = current.next current.next = previous previous = current current = next_node return previous
Why Save next_node?
Consider:
current.next = previous
We’ve just destroyed the original forward link.
Without:
next_node = current.next
we would lose the rest of the list.
Complexity
Time: O(n)Space: O(1)
A recursive version is also possible, but uses O(n) recursion stack space.
Typical follow-up: Reverse the list recursively.
8. Validate a Binary Search Tree
The Question
Determine whether a binary tree is a valid BST.
A common mistake is checking only:
left < node < right
That isn’t sufficient.
Consider:
10
/ \
5 15
/
6
6 is smaller than 15, but it is still invalid because it belongs to the right subtree of 10.
The Idea
Every node has a valid range.
For the root:
(-ā, +ā)
For its left child:
(-ā, root)
For its right child:
(root, +ā)
Solution
def is_valid_bst(root): def validate(node, low, high): if not node: return True if node.val <= low or node.val >= high: return False return ( validate(node.left, low, node.val) and validate(node.right, node.val, high) ) return validate(root, float("-inf"), float("inf"))
Complexity
Time: O(n)Space: O(h)
where h is the height of the tree.
An alternative solution uses inorder traversal because a valid BST produces a strictly increasing inorder sequence.
Typical follow-up: Can you solve it iteratively?
9. Number of Islands
The Question
Given a grid of land (1) and water (0), count the number of islands.
[ ["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"]]
Output:
3
The Idea
Every time we find an unvisited 1, we’ve discovered a new island.
Run DFS to visit every connected piece of land.
Think of it as:
Find land āStart DFS āVisit connected land āMark visited āCount +1
Solution
def num_islands(grid): if not grid: return 0 rows = len(grid) cols = len(grid[0]) count = 0 def dfs(row, col): if row < 0 or row >= rows: return if col < 0 or col >= cols: return if grid[row][col] != "1": return # Mark as visited grid[row][col] = "0" dfs(row + 1, col) dfs(row - 1, col) dfs(row, col + 1) dfs(row, col - 1) for row in range(rows): for col in range(cols): if grid[row][col] == "1": count += 1 dfs(row, col) return count
Complexity
Time: O(rows Ć cols)Space: O(rows Ć cols) worst case
This is a classic example of a graph traversal problem disguised as a matrix problem.
Typical follow-up: Can you solve it using BFS instead of DFS?
10. Course Schedule
The Question
You have numCourses courses and prerequisite relationships.
For example:
[1, 0]
means:
Take course 0 before course 1.
Determine whether all courses can be completed.
The Trick
This isn’t really a scheduling problem.
It’s a directed graph cycle detection problem.
If we have:
0 ā 1ā āāāāāā
there is a cycle.
Therefore, the courses cannot all be completed.
Solution: Kahn’s Algorithm
from collections import defaultdict, dequedef can_finish(num_courses, prerequisites): graph = defaultdict(list) indegree = [0] * num_courses for course, prerequisite in prerequisites: graph[prerequisite].append(course) indegree[course] += 1 queue = deque() for course in range(num_courses): if indegree[course] == 0: queue.append(course) completed = 0 while queue: current = queue.popleft() completed += 1 for next_course in graph[current]: indegree[next_course] -= 1 if indegree[next_course] == 0: queue.append(next_course) return completed == num_courses
The Reasoning
Courses with:
indegree = 0
have no remaining prerequisites.
We process them, remove their dependency from other courses, and continue.
If we eventually process every course:
completed == num_courses
the schedule is possible.
Otherwise, a cycle exists.
Complexity
Time: O(V + E)Space: O(V + E)
The alternative approach is DFS-based cycle detection.
What Are These 10 Questions Really Testing?
The important part isn’t memorizing ten pieces of code.
It’s recognizing the underlying pattern.
If you see… Think… Pair adding to target Hash Map Maximum contiguous sum Kadane’s Algorithm Rotated sorted array Binary Search Prefix/suffix products Prefix + Suffix Unique substring Sliding Window Constant-time cache Hash Map + Doubly Linked List Reverse linked list Pointer Manipulation BST validation Range Checking / Inorder Connected cells DFS / BFS Prerequisites Graph + Topological Sort
These patterns form a large part of the core DSA toolkit covered by the larger preparation guide.
And This Is Only the Preview
There are 25 more problems in the full 25-question preparation set, including:
- Reverse String
- Valid Palindrome
- Move Zeroes
- Merge Intervals
- Find First and Last Position
- Trapping Rain Water
- Valid Parentheses
- Group Anagrams
- Implement
strStr() - Detect Cycle in Linked List
- Merge Two Sorted Linked Lists
- Add Two Numbers
- Binary Tree Level Order Traversal
- Lowest Common Ancestor
- Clone Graph
The full guide also goes into brute-force vs optimized solutions, alternative approaches, common mistakes, edge cases, complexity analysis, follow-up questions, interview communication, and an actual practice plan rather than simply throwing 25 answers at you.
š„ Video Walkthroughs Are Coming
We’re also preparing video walkthroughs for these problems.
The goal isn’t just to show the final code. The walkthroughs will break down how to recognize the pattern, how to reason through the solution, and how to respond when the interviewer changes the constraints.
Video walkthroughs will drop shortly on The CyberSec Guru.
Want to Go Deeper?
If you’re serious about interview preparation, the 10 questions is only the starting point.
There is a much deeper version being put together for readers who want to go beyond the usual “here’s the LeetCode answer” approach, with more interview-focused explanations, additional problems, patterns, follow-ups, and preparation material.
Explore the full interview-prep experience and keep an eye out for the upcoming interview guides.
The objective is simple:
Don’t memorize the solution. Learn how to solve the problem when the interviewer changes it.









