Coding Test Complete Preparation Guide | From Algorithms to Practical Tips
이 글의 핵심
Coding test complete preparation guide with detailed explanation of essential algorithms, problem-solving strategies, and practical tips.
Introduction: Coding Tests Are All About Preparation
”I Failed Because I Didn’t Know Algorithms”
Coding tests are pattern recognition. Anyone can pass by learning frequently appearing patterns and practicing repeatedly.
What This Guide Covers:
- Essential algorithms and data structures
- Problem-solving patterns
- Time management strategy
- Language selection guide
- Practical tips
Table of Contents
- Essential Algorithms
- Essential Data Structures
- Problem-Solving Patterns
- Time Management
- Language Selection
- Practical Tips
- Summary
1. Essential Algorithms
Learning Order by Priority
graph TB
A[Coding Test Algorithms] --> B[Stage 1: Essential]
A --> C[Stage 2: Important]
A --> D[Stage 3: Advanced]
B --> B1[Two Pointers]
B --> B2[Sliding Window]
B --> B3[Binary Search]
B --> B4[BFS/DFS]
C --> C1[Dynamic Programming]
C --> C2[Greedy]
C --> C3[Backtracking]
D --> D1[Shortest Path]
D --> D2[Topological Sort]
D --> D3[Trie]
Stage 1: Essential Algorithms (High Frequency)
Two Pointers:
# Example: Two sum in sorted array
def two_sum(arr, target):
left, right = 0, len(arr) - 1
while left < right:
current_sum = arr[left] + arr[right]
if current_sum == target:
return [left, right]
elif current_sum < target:
left += 1
else:
right -= 1
return None
# Time complexity: O(n)
Sliding Window:
# Example: Maximum sum subarray of length k
def max_sum_subarray(arr, k):
window_sum = sum(arr[:k])
max_sum = window_sum
for i in range(k, len(arr)):
window_sum += arr[i] - arr[i - k]
max_sum = max(max_sum, window_sum)
return max_sum
# Time complexity: O(n)
Binary Search:
# Example: Find value in sorted array
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
# Time complexity: O(log n)
BFS/DFS (Breadth/Depth First Search):
from collections import deque
# BFS
def bfs(graph, start):
visited = set()
queue = deque([start])
visited.add(start)
while queue:
node = queue.popleft()
print(node)
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
# DFS (recursive)
def dfs(graph, node, visited=None):
if visited is None:
visited = set()
visited.add(node)
print(node)
for neighbor in graph[node]:
if neighbor not in visited:
dfs(graph, neighbor, visited)
Stage 2: Important Algorithms
Dynamic Programming (DP):
# Example: Fibonacci sequence
def fibonacci(n):
if n <= 1:
return n
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
# Time complexity: O(n)
# Space complexity: O(n)
Greedy:
# Example: Coin change
def coin_change(coins, amount):
coins.sort(reverse=True)
count = 0
for coin in coins:
if amount >= coin:
count += amount // coin
amount %= coin
return count if amount == 0 else -1
2. Essential Data Structures
Learning by Priority
| Priority | Data Structure | Frequency | Difficulty |
|---|---|---|---|
| 1 | Array | Very High | Easy |
| 2 | HashMap | Very High | Easy |
| 3 | Stack | High | Easy |
| 4 | Queue | High | Easy |
| 5 | Heap | Medium | Medium |
| 6 | Tree | Medium | Medium |
| 7 | Graph | Medium | Hard |
Core Operations by Data Structure
Array:
# Essential operations
arr = [1, 2, 3, 4, 5]
arr.append(6) # Add at end O(1)
arr.pop() # Remove from end O(1)
arr.insert(0, 0) # Add at front O(n)
arr.remove(3) # Remove value O(n)
arr.sort() # Sort O(n log n)
HashMap:
# Essential operations
d = {}
d['key'] = 'value' # Insert O(1)
val = d.get('key') # Lookup O(1)
del d['key'] # Delete O(1)
'key' in d # Check existence O(1)
Stack:
# Stack (LIFO)
stack = []
stack.append(1) # push
stack.append(2)
top = stack.pop() # pop (2)
Queue:
from collections import deque
# Queue (FIFO)
queue = deque()
queue.append(1) # enqueue
queue.append(2)
front = queue.popleft() # dequeue (1)
Heap:
import heapq
# Min heap
heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 2)
min_val = heapq.heappop(heap) # 1
# Max heap (use negative)
max_heap = []
heapq.heappush(max_heap, -3)
heapq.heappush(max_heap, -1)
max_val = -heapq.heappop(max_heap) # 3
3. Problem-Solving Patterns
Pattern Recognition Flowchart
flowchart TD
A[Read Problem] --> B{Sorted Array?}
B -->|Yes| C[Binary Search or Two Pointers]
B -->|No| D{Subarray/Substring?}
D -->|Yes| E[Sliding Window]
D -->|No| F{Graph/Tree?}
F -->|Yes| G[BFS/DFS]
F -->|No| H{Optimization Problem?}
H -->|Yes| I[DP or Greedy]
H -->|No| J[HashMap or Stack/Queue]
Examples by Pattern
Pattern 1: Two Pointers
# LeetCode 15. 3Sum
def three_sum(nums):
nums.sort()
result = []
for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i-1]:
continue
left, right = i + 1, len(nums) - 1
while left < right:
total = nums[i] + nums[left] + nums[right]
if total == 0:
result.append([nums[i], nums[left], nums[right]])
left += 1
right -= 1
while left < right and nums[left] == nums[left-1]:
left += 1
elif total < 0:
left += 1
else:
right -= 1
return result
Pattern 2: Sliding Window
# LeetCode 3. Longest Substring Without Repeating Characters
def length_of_longest_substring(s):
char_set = set()
left = 0
max_length = 0
for right in range(len(s)):
while s[right] in char_set:
char_set.remove(s[left])
left += 1
char_set.add(s[right])
max_length = max(max_length, right - left + 1)
return max_length
Pattern 3: BFS
# LeetCode 102. Binary Tree Level Order Traversal
from collections import deque
def level_order(root):
if not root:
return []
result = []
queue = deque([root])
while queue:
level_size = len(queue)
level = []
for _ in range(level_size):
node = queue.popleft()
level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(level)
return result
Pattern 4: Dynamic Programming
# LeetCode 70. Climbing Stairs
def climb_stairs(n):
if n <= 2:
return n
dp = [0] * (n + 1)
dp[1], dp[2] = 1, 2
for i in range(3, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
4. Time Management
Exam Time Allocation (2 hours, 4 problems)
Total time: 120 minutes
Problem 1 (Easy): 20 minutes
Problem 2 (Medium): 30 minutes
Problem 3 (Medium): 35 minutes
Problem 4 (Hard): 35 minutes
Buffer time: 10 minutes (review and debugging)
Problem-Solving Process
flowchart LR
A[Read Problem 3min] --> B[Analyze Examples 2min]
B --> C[Design Approach 5min]
C --> D[Write Code 15min]
D --> E[Test 3min]
E --> F[Debug 2min]
Checklist for Each Stage:
1. Read Problem (3 min):
- Check input format
- Check output format
- Check constraints (n range, time limit)
- Identify edge cases
2. Analyze Examples (2 min):
- Trace example input/output by hand
- Pattern recognition
- Think about exception cases
3. Design Approach (5 min):
- Calculate brute force time complexity
- Consider optimization methods
- Select data structures
- Write pseudocode
4. Write Code (15 min):
- Write function signature
- Implement core logic
- Handle edge cases
5. Test (3 min):
- Test with example inputs
- Test edge cases (empty array, size 1, max size)
- Check output format
6. Debug (2 min):
- Check error messages
- Print debugging
- Fix logic errors
5. Language Selection
Pros and Cons by Language
| Language | Pros | Cons | Recommended For |
|---|---|---|---|
| Python | Concise syntax, fast implementation | Slow speed (TLE possible) | Most cases |
| C++ | Fast speed, STL | Long code, debugging difficulty | Performance-critical problems |
| Java | Stable, rich API | Verbose syntax | Enterprise background |
| JavaScript | Familiar to web developers | Lack of type safety | Web developers |
Why Python is Recommended
1. Concise Syntax:
# Python (5 lines)
def reverse_string(s):
return s[::-1]
# C++ (10 lines)
#include <string>
#include <algorithm>
string reverseString(string s) {
reverse(s.begin(), s.end());
return s;
}
2. Rich Built-in Functions:
# Sorting
arr.sort()
# Max/Min
max_val = max(arr)
min_val = min(arr)
# Sum
total = sum(arr)
# Count
from collections import Counter
count = Counter(arr)
3. Slicing:
arr = [1, 2, 3, 4, 5]
arr[1:4] # [2, 3, 4]
arr[::-1] # [5, 4, 3, 2, 1] (reverse)
arr[::2] # [1, 3, 5] (every 2)
When to Use C++
When TLE (Time Limit Exceeded) Occurs:
Problem constraint: n ≤ 10^6, time limit 1 second
Python: 10^6 operations → 1 second (tight)
C++: 10^6 operations → 0.1 second (comfortable)
→ Switch to C++ if Python gets TLE
C++ STL Essentials:
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
// Vector
vector<int> v = {1, 2, 3};
v.push_back(4);
// Sort
sort(v.begin(), v.end());
// Binary search
bool found = binary_search(v.begin(), v.end(), 3);
// Priority queue (max heap)
priority_queue<int> pq;
pq.push(3);
int top = pq.top();
6. Practical Tips
Tip 1: Prepare Templates
Python Template:
# Input processing
n = int(input())
arr = list(map(int, input().split()))
# Or
import sys
input = sys.stdin.readline
# Output
print(result)
C++ Template:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> arr(n);
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
// Logic
cout << result << endl;
return 0;
}
Tip 2: Time Complexity Check
Estimate time complexity from n range:
n ≤ 10: O(n!) possible
n ≤ 20: O(2^n) possible
n ≤ 100: O(n³) possible
n ≤ 1,000: O(n²) possible
n ≤ 10,000: O(n² / 2) possible
n ≤ 100,000: O(n log n) needed
n ≤ 1,000,000: O(n) needed
n > 1,000,000: O(log n) or O(1) needed
Tip 3: Debugging Strategy
# Print debugging
def solve(arr):
print(f"DEBUG: arr = {arr}") # Check input
result = []
for i in range(len(arr)):
print(f"DEBUG: i = {i}, arr[i] = {arr[i]}") # Check process
result.append(arr[i] * 2)
print(f"DEBUG: result = {result}") # Check output
return result
Tip 4: Edge Case Check
# Cases to always test
test_cases = [
[], # Empty array
[1], # Size 1
[1, 1, 1], # All same values
[1, 2, 3], # Sorted array
[3, 2, 1], # Reverse order
[-1, 0, 1], # Contains negative
[10**9], # Max value
]
Tip 5: Common Mistakes to Avoid
1. Off-by-one errors:
# ❌ Wrong
for i in range(len(arr) - 1): # Misses last element
# ✅ Correct
for i in range(len(arr)):
2. Integer overflow:
# Python: No overflow (arbitrary precision)
# C++: Use long long for large numbers
long long result = (long long)a * b;
3. Modifying while iterating:
# ❌ Wrong
for item in arr:
if condition:
arr.remove(item) # Modifies during iteration
# ✅ Correct
arr = [item for item in arr if not condition]
7. Summary
3-Month Study Plan
Month 1: Build Foundation
- Array, HashMap, Stack, Queue
- Two Pointers, Sliding Window
- LeetCode Easy 50 problems
Month 2: Intermediate Algorithms
- BFS/DFS, Binary Search
- Dynamic Programming basics
- LeetCode Medium 50 problems
Month 3: Advanced Algorithms
- Advanced Dynamic Programming
- Graph algorithms
- LeetCode Medium 50 + Hard 20 problems
Study Resources
Online Judges:
- LeetCode - Global standard
- HackerRank - Interview prep
- Codeforces - Competitive programming
Recommended Problem Sets:
- LeetCode Top 100 Liked
- LeetCode Blind 75
- NeetCode 150
Next Steps
For detailed algorithm explanations, refer to these series:
- Algorithm Series #1: Array and List
- Algorithm Series #10: BFS/DFS
- Algorithm Series #12: Dynamic Programming
Related Topics:
- Time Complexity Optimization Checklist
- Two Pointers Pattern
- Sliding Window Pattern
Quick Study Guide
Week 1-2: Arrays, HashMap basics
Week 3-4: Two Pointers, Sliding Window
Week 5-6: Stack, Queue, BFS/DFS
Week 7-8: Binary Search, Sorting
Week 9-10: Dynamic Programming basics
Week 11-12: Advanced DP, Greedy, Backtracking
Practice Schedule
Daily routine (2-3 hours):
1. Review 1 concept (30 min)
2. Solve 2 new problems (60 min)
3. Review 1 past problem (30 min)
Weekly:
- Monday-Friday: New problems
- Saturday: Mock test (4 problems, 2 hours)
- Sunday: Review wrong answers
Keywords
Coding Test, Algorithm, Data Structure, LeetCode, Interview, Two Pointers, Sliding Window, BFS, DFS, Dynamic Programming, Binary Search, Python, C++