Interview Questions - Easy
Easy-level algorithm interview questions with detailed approach explanations and solutions.
How to Approach Interview Problems
- Clarify requirements: Ask about edge cases, constraints, input/output format
- Think out loud: Explain your thought process
- Start with brute force: Then optimize
- Consider trade-offs: Time vs. space complexity
- Test with examples: Walk through your solution
- Handle edge cases: Empty input, single element, duplicates
Problem 1: Two Sum
Problem: Given an array of integers and a target, return indices of two numbers that add up to target.
Example:
1Input: nums = [2,7,11,15], target = 9
2Output: [0,1]
3Explanation: nums[0] + nums[1] = 2 + 7 = 9
Approach
Brute Force ($O(n^2)$): Check all pairs
1for i := 0; i < len(nums); i++ {
2 for j := i+1; j < len(nums); j++ {
3 if nums[i] + nums[j] == target {
4 return []int{i, j}
5 }
6 }
7}
Optimized ($O(n)$): Use hash map to store complements
Key Insight: For each number, check if its complement (target - num) exists in map.
Solution
1func twoSum(nums []int, target int) []int {
2 seen := make(map[int]int) // value -> index
3
4 for i, num := range nums {
5 complement := target - num
6
7 if j, exists := seen[complement]; exists {
8 return []int{j, i}
9 }
10
11 seen[num] = i
12 }
13
14 return nil
15}
Time: $O(n)$, Space: $O(n)$
Why this works: We build the map as we go, so when we find a complement, we know its index.
Problem 2: Valid Parentheses
Problem: Determine if string of brackets is valid (every opening has matching closing in correct order).
Example:
1Input: s = "()[]{}"
2Output: true
3
4Input: s = "([)]"
5Output: false
Approach
Key Insight: Use stack - opening brackets push, closing brackets must match top of stack.
Steps:
- For each character:
- If opening bracket: push to stack
- If closing bracket: check if matches stack top, pop if yes
- Stack should be empty at end
Solution
1func isValid(s string) bool {
2 stack := []rune{}
3 pairs := map[rune]rune{')': '(', '}': '{', ']': '['}
4
5 for _, char := range s {
6 // Opening bracket
7 if char == '(' || char == '{' || char == '[' {
8 stack = append(stack, char)
9 } else {
10 // Closing bracket
11 if len(stack) == 0 || stack[len(stack)-1] != pairs[char] {
12 return false
13 }
14 stack = stack[:len(stack)-1] // Pop
15 }
16 }
17
18 return len(stack) == 0
19}
Time: $O(n)$, Space: $O(n)$
Edge cases: Empty string (valid), unmatched opening, unmatched closing
Problem 3: Merge Two Sorted Lists
Problem: Merge two sorted linked lists into one sorted list.
Example:
1Input: list1 = [1,2,4], list2 = [1,3,4]
2Output: [1,1,2,3,4,4]
Approach
Key Insight: Use two pointers, always pick smaller value.
Technique: Dummy node to simplify edge cases.
Solution
1func mergeTwoLists(l1, l2 *ListNode) *ListNode {
2 dummy := &ListNode{}
3 curr := dummy
4
5 for l1 != nil && l2 != nil {
6 if l1.Val <= l2.Val {
7 curr.Next = l1
8 l1 = l1.Next
9 } else {
10 curr.Next = l2
11 l2 = l2.Next
12 }
13 curr = curr.Next
14 }
15
16 // Attach remaining nodes
17 if l1 != nil {
18 curr.Next = l1
19 } else {
20 curr.Next = l2
21 }
22
23 return dummy.Next
24}
Time: $O(m + n)$, Space: $O(1)$
Why dummy node: Avoids special case for first node.
Problem 4: Best Time to Buy and Sell Stock
Problem: Find maximum profit from one buy and one sell (buy before sell).
Example:
1Input: prices = [7,1,5,3,6,4]
2Output: 5
3Explanation: Buy at 1, sell at 6, profit = 5
Approach
Key Insight: Track minimum price seen so far, calculate profit at each step.
Pattern: Single pass, keep running minimum.
Solution
1func maxProfit(prices []int) int {
2 if len(prices) == 0 {
3 return 0
4 }
5
6 minPrice := prices[0]
7 maxProfit := 0
8
9 for _, price := range prices {
10 if price < minPrice {
11 minPrice = price
12 } else if price - minPrice > maxProfit {
13 maxProfit = price - minPrice
14 }
15 }
16
17 return maxProfit
18}
Time: $O(n)$, Space: $O(1)$
Why this works: At each point, we know the best buy price before this point.
Problem 5: Valid Palindrome
Problem: Check if string is palindrome (ignoring non-alphanumeric, case-insensitive).
Example:
1Input: s = "A man, a plan, a canal: Panama"
2Output: true
Approach
Key Insight: Two pointers from both ends, skip non-alphanumeric.
Solution
1import "unicode"
2
3func isPalindrome(s string) bool {
4 left, right := 0, len(s)-1
5
6 for left < right {
7 // Skip non-alphanumeric from left
8 for left < right && !isAlphaNumeric(rune(s[left])) {
9 left++
10 }
11
12 // Skip non-alphanumeric from right
13 for left < right && !isAlphaNumeric(rune(s[right])) {
14 right--
15 }
16
17 // Compare (case-insensitive)
18 if unicode.ToLower(rune(s[left])) != unicode.ToLower(rune(s[right])) {
19 return false
20 }
21
22 left++
23 right--
24 }
25
26 return true
27}
28
29func isAlphaNumeric(ch rune) bool {
30 return unicode.IsLetter(ch) || unicode.IsDigit(ch)
31}
Time: $O(n)$, Space: $O(1)$
Problem 6: Reverse Linked List
Problem: Reverse a singly linked list.
Example:
1Input: 1 -> 2 -> 3 -> 4 -> 5
2Output: 5 -> 4 -> 3 -> 2 -> 1
Approach
Key Insight: Three pointers - prev, curr, next.
Steps:
- Save next node
- Reverse current node's pointer
- Move all pointers forward
Solution
1func reverseList(head *ListNode) *ListNode {
2 var prev *ListNode
3 curr := head
4
5 for curr != nil {
6 next := curr.Next // Save next
7 curr.Next = prev // Reverse pointer
8 prev = curr // Move prev forward
9 curr = next // Move curr forward
10 }
11
12 return prev // New head
13}
Time: $O(n)$, Space: $O(1)$
Common mistake: Forgetting to save next before changing curr.Next.
Problem 7: Contains Duplicate
Problem: Check if array contains any duplicate values.
Example:
1Input: nums = [1,2,3,1]
2Output: true
Approach
Key Insight: Use hash set to track seen values.
Solution
1func containsDuplicate(nums []int) bool {
2 seen := make(map[int]bool)
3
4 for _, num := range nums {
5 if seen[num] {
6 return true
7 }
8 seen[num] = true
9 }
10
11 return false
12}
Time: $O(n)$, Space: $O(n)$
Alternative: Sort first ($O(n \log n)$ time, $O(1)$ space), then check adjacent elements.
Problem 8: Maximum Subarray (Kadane's Algorithm)
Problem: Find contiguous subarray with largest sum.
Example:
1Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
2Output: 6
3Explanation: [4,-1,2,1] has sum 6
Approach
Key Insight: At each position, decide: extend current subarray or start new one.
Kadane's Algorithm: Keep running sum, reset if it goes negative.
Solution
1func maxSubArray(nums []int) int {
2 maxSum := nums[0]
3 currentSum := nums[0]
4
5 for i := 1; i < len(nums); i++ {
6 // Either extend current or start new
7 currentSum = max(nums[i], currentSum + nums[i])
8 maxSum = max(maxSum, currentSum)
9 }
10
11 return maxSum
12}
13
14func max(a, b int) int {
15 if a > b {
16 return a
17 }
18 return b
19}
Time: $O(n)$, Space: $O(1)$
Why this works: If current sum becomes negative, it can't help future sums.
Problem 9: Climbing Stairs
Problem: How many distinct ways to climb n stairs (1 or 2 steps at a time)?
Example:
1Input: n = 3
2Output: 3
3Explanation: 1+1+1, 1+2, 2+1
Approach
Key Insight: To reach step n, you came from step n-1 or n-2.
Recurrence: $f(n) = f(n-1) + f(n-2)$ (Fibonacci!)
Solution
1func climbStairs(n int) int {
2 if n <= 2 {
3 return n
4 }
5
6 prev2, prev1 := 1, 2
7
8 for i := 3; i <= n; i++ {
9 curr := prev1 + prev2
10 prev2 = prev1
11 prev1 = curr
12 }
13
14 return prev1
15}
Time: $O(n)$, Space: $O(1)$
Common mistake: Using recursion without memoization ($O(2^n)$ time).
Problem 10: Binary Tree Maximum Depth
Problem: Find maximum depth of binary tree.
Example:
1Input: root = [3,9,20,null,null,15,7]
2Output: 3
Approach
Key Insight: Depth = 1 + max(left depth, right depth).
Pattern: Recursive tree traversal.
Solution
1func maxDepth(root *TreeNode) int {
2 if root == nil {
3 return 0
4 }
5
6 leftDepth := maxDepth(root.Left)
7 rightDepth := maxDepth(root.Right)
8
9 return 1 + max(leftDepth, rightDepth)
10}
Time: $O(n)$, Space: $O(h)$ where h is height (recursion stack)
Iterative version: Use level-order traversal (BFS) and count levels.
Common Patterns in Easy Problems
- Hash Map/Set: Two sum, contains duplicate
- Two Pointers: Valid palindrome, merge lists
- Stack: Valid parentheses
- Sliding Window: Maximum subarray
- Dynamic Programming: Climbing stairs
- Tree Recursion: Maximum depth
- Linked List: Reverse, merge
Interview Tips
✅ Do:
- Ask clarifying questions
- Start with brute force
- Explain your thinking
- Test with examples
- Consider edge cases
❌ Don't:
- Jump to code immediately
- Assume constraints
- Stay silent
- Ignore edge cases
- Give up if stuck
Time Management
- 5 min: Understand problem, ask questions
- 10 min: Discuss approach, consider alternatives
- 20 min: Code solution
- 5 min: Test and debug
Total: ~40 minutes per problem
Related Snippets
- Common Interview Challenges
A curated collection of the most common algorithm interview problems with … - Interview Questions - Hard
Hard-level algorithm interview questions with detailed approach explanations and … - Interview Questions - Medium
Medium-level algorithm interview questions with detailed approach explanations …