Initial commit
This commit is contained in:
485
skills/leetcode-teacher/references/data_structures.md
Normal file
485
skills/leetcode-teacher/references/data_structures.md
Normal file
@@ -0,0 +1,485 @@
|
||||
# Data Structures Reference
|
||||
|
||||
Essential data structures for technical interviews with implementation patterns.
|
||||
|
||||
## Arrays
|
||||
|
||||
**Use when:** Sequential data, random access needed
|
||||
**Time:** Access O(1), Search O(n), Insert/Delete O(n)
|
||||
**Space:** O(n)
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
# Reverse
|
||||
arr[::-1]
|
||||
|
||||
# Two pointers
|
||||
left, right = 0, len(arr) - 1
|
||||
|
||||
# Sliding window
|
||||
for end in range(len(arr)):
|
||||
window.add(arr[end])
|
||||
if end >= k:
|
||||
window.remove(arr[end - k])
|
||||
```
|
||||
|
||||
### Product Example: Instagram Feed
|
||||
```python
|
||||
class InstagramFeed:
|
||||
def __init__(self):
|
||||
self.posts = [] # Array of posts
|
||||
|
||||
def add_post(self, post):
|
||||
self.posts.insert(0, post) # New posts at beginning
|
||||
|
||||
def get_feed(self, start, limit):
|
||||
return self.posts[start:start + limit]
|
||||
```
|
||||
|
||||
## Hash Maps
|
||||
|
||||
**Use when:** Fast lookups, counting, caching
|
||||
**Time:** O(1) average for all operations
|
||||
**Space:** O(n)
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
# Frequency counter
|
||||
freq = {}
|
||||
for item in items:
|
||||
freq[item] = freq.get(item, 0) + 1
|
||||
|
||||
# Two sum
|
||||
seen = {}
|
||||
for i, num in enumerate(nums):
|
||||
complement = target - num
|
||||
if complement in seen:
|
||||
return [seen[complement], i]
|
||||
seen[num] = i
|
||||
```
|
||||
|
||||
### Product Example: Twitter Hashtags
|
||||
```python
|
||||
class TrendingHashtags:
|
||||
def __init__(self):
|
||||
self.hashtag_count = {}
|
||||
|
||||
def process_tweet(self, tweet):
|
||||
for hashtag in tweet.hashtags:
|
||||
self.hashtag_count[hashtag] = \
|
||||
self.hashtag_count.get(hashtag, 0) + 1
|
||||
|
||||
def get_trending(self, k):
|
||||
return sorted(self.hashtag_count.items(),
|
||||
key=lambda x: x[1], reverse=True)[:k]
|
||||
```
|
||||
|
||||
## Linked Lists
|
||||
|
||||
**Use when:** Frequent insertions/deletions, unknown size
|
||||
**Time:** Access O(n), Insert/Delete O(1) at known position
|
||||
**Space:** O(n)
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
# Fast & slow pointers (detect cycle)
|
||||
slow = fast = head
|
||||
while fast and fast.next:
|
||||
slow = slow.next
|
||||
fast = fast.next.next
|
||||
if slow == fast:
|
||||
return True
|
||||
|
||||
# Reverse linked list
|
||||
prev = None
|
||||
curr = head
|
||||
while curr:
|
||||
next_node = curr.next
|
||||
curr.next = prev
|
||||
prev = curr
|
||||
curr = next_node
|
||||
```
|
||||
|
||||
### Product Example: Browser History
|
||||
```python
|
||||
class BrowserHistory:
|
||||
def __init__(self):
|
||||
self.current = None
|
||||
|
||||
def visit(self, url):
|
||||
new_page = Page(url)
|
||||
new_page.prev = self.current
|
||||
if self.current:
|
||||
self.current.next = new_page
|
||||
self.current = new_page
|
||||
|
||||
def back(self):
|
||||
if self.current and self.current.prev:
|
||||
self.current = self.current.prev
|
||||
return self.current.url
|
||||
|
||||
def forward(self):
|
||||
if self.current and self.current.next:
|
||||
self.current = self.current.next
|
||||
return self.current.url
|
||||
```
|
||||
|
||||
## Stacks
|
||||
|
||||
**Use when:** LIFO, backtracking, parsing
|
||||
**Time:** O(1) for push/pop
|
||||
**Space:** O(n)
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
# Valid parentheses
|
||||
stack = []
|
||||
pairs = {'(': ')', '[': ']', '{': '}'}
|
||||
|
||||
for char in s:
|
||||
if char in pairs:
|
||||
stack.append(char)
|
||||
elif not stack or pairs[stack.pop()] != char:
|
||||
return False
|
||||
|
||||
return len(stack) == 0
|
||||
```
|
||||
|
||||
### Product Example: Code Editor Undo/Redo
|
||||
```python
|
||||
class CodeEditor:
|
||||
def __init__(self):
|
||||
self.undo_stack = []
|
||||
self.redo_stack = []
|
||||
self.content = ""
|
||||
|
||||
def type(self, text):
|
||||
self.undo_stack.append(self.content)
|
||||
self.content += text
|
||||
self.redo_stack.clear()
|
||||
|
||||
def undo(self):
|
||||
if self.undo_stack:
|
||||
self.redo_stack.append(self.content)
|
||||
self.content = self.undo_stack.pop()
|
||||
|
||||
def redo(self):
|
||||
if self.redo_stack:
|
||||
self.undo_stack.append(self.content)
|
||||
self.content = self.redo_stack.pop()
|
||||
```
|
||||
|
||||
## Queues
|
||||
|
||||
**Use when:** FIFO, BFS, scheduling
|
||||
**Time:** O(1) for enqueue/dequeue
|
||||
**Space:** O(n)
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
# BFS
|
||||
queue = deque([start])
|
||||
visited = {start}
|
||||
|
||||
while queue:
|
||||
node = queue.popleft()
|
||||
for neighbor in node.neighbors:
|
||||
if neighbor not in visited:
|
||||
visited.add(neighbor)
|
||||
queue.append(neighbor)
|
||||
```
|
||||
|
||||
### Product Example: Uber Request Queue
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
class UberQueue:
|
||||
def __init__(self):
|
||||
self.requests = deque()
|
||||
|
||||
def add_request(self, rider, location):
|
||||
self.requests.append({
|
||||
'rider': rider,
|
||||
'location': location,
|
||||
'timestamp': time.time()
|
||||
})
|
||||
|
||||
def match_driver(self, driver):
|
||||
if self.requests:
|
||||
request = self.requests.popleft()
|
||||
return request
|
||||
return None
|
||||
```
|
||||
|
||||
## Heaps (Priority Queues)
|
||||
|
||||
**Use when:** Top K, median, scheduling by priority
|
||||
**Time:** O(log n) insert/delete, O(1) peek
|
||||
**Space:** O(n)
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
import heapq
|
||||
|
||||
# Top K elements (min heap)
|
||||
min_heap = []
|
||||
for num in nums:
|
||||
heapq.heappush(min_heap, num)
|
||||
if len(min_heap) > k:
|
||||
heapq.heappop(min_heap)
|
||||
|
||||
# K closest points (max heap with negation)
|
||||
max_heap = []
|
||||
for point in points:
|
||||
dist = -distance(point) # Negative for max heap
|
||||
heapq.heappush(max_heap, (dist, point))
|
||||
if len(max_heap) > k:
|
||||
heapq.heappop(max_heap)
|
||||
```
|
||||
|
||||
### Product Example: Uber Driver Matching
|
||||
```python
|
||||
import heapq
|
||||
|
||||
class UberMatching:
|
||||
def __init__(self):
|
||||
self.available_drivers = [] # Min heap by distance
|
||||
|
||||
def add_driver(self, driver, distance):
|
||||
heapq.heappush(self.available_drivers, (distance, driver))
|
||||
|
||||
def match_closest_driver(self):
|
||||
if self.available_drivers:
|
||||
distance, driver = heapq.heappop(self.available_drivers)
|
||||
return driver
|
||||
return None
|
||||
```
|
||||
|
||||
## Trees (Binary Trees)
|
||||
|
||||
**Use when:** Hierarchical data, BST operations
|
||||
**Time:** O(log n) balanced, O(n) worst case
|
||||
**Space:** O(h) for recursion
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
# Inorder traversal (DFS)
|
||||
def inorder(root):
|
||||
if not root:
|
||||
return []
|
||||
return inorder(root.left) + [root.val] + inorder(root.right)
|
||||
|
||||
# Level order (BFS)
|
||||
def levelOrder(root):
|
||||
if not root:
|
||||
return []
|
||||
result, queue = [], deque([root])
|
||||
while queue:
|
||||
level = []
|
||||
for _ in range(len(queue)):
|
||||
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
|
||||
```
|
||||
|
||||
### Product Example: File System
|
||||
```python
|
||||
class FileSystem:
|
||||
def __init__(self):
|
||||
self.root = Directory("/")
|
||||
|
||||
def create_path(self, path):
|
||||
parts = path.split("/")[1:] # Skip empty first element
|
||||
current = self.root
|
||||
|
||||
for part in parts:
|
||||
if part not in current.children:
|
||||
current.children[part] = Directory(part)
|
||||
current = current.children[part]
|
||||
|
||||
return current
|
||||
|
||||
def find(self, path):
|
||||
parts = path.split("/")[1:]
|
||||
current = self.root
|
||||
|
||||
for part in parts:
|
||||
if part not in current.children:
|
||||
return None
|
||||
current = current.children[part]
|
||||
|
||||
return current
|
||||
```
|
||||
|
||||
## Graphs
|
||||
|
||||
**Use when:** Networks, relationships, dependencies
|
||||
**Time:** BFS/DFS O(V + E)
|
||||
**Space:** O(V + E) for adjacency list
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
# Adjacency list representation
|
||||
graph = {
|
||||
'A': ['B', 'C'],
|
||||
'B': ['D'],
|
||||
'C': ['D'],
|
||||
'D': []
|
||||
}
|
||||
|
||||
# DFS
|
||||
def dfs(node, visited=set()):
|
||||
if node in visited:
|
||||
return
|
||||
visited.add(node)
|
||||
for neighbor in graph[node]:
|
||||
dfs(neighbor, visited)
|
||||
|
||||
# BFS
|
||||
def bfs(start):
|
||||
visited = {start}
|
||||
queue = deque([start])
|
||||
while queue:
|
||||
node = queue.popleft()
|
||||
for neighbor in graph[node]:
|
||||
if neighbor not in visited:
|
||||
visited.add(neighbor)
|
||||
queue.append(neighbor)
|
||||
```
|
||||
|
||||
### Product Example: Social Network
|
||||
```python
|
||||
class SocialNetwork:
|
||||
def __init__(self):
|
||||
self.friends = {} # user_id -> [friend_ids]
|
||||
|
||||
def add_friendship(self, user1, user2):
|
||||
if user1 not in self.friends:
|
||||
self.friends[user1] = []
|
||||
if user2 not in self.friends:
|
||||
self.friends[user2] = []
|
||||
|
||||
self.friends[user1].append(user2)
|
||||
self.friends[user2].append(user1)
|
||||
|
||||
def degrees_of_separation(self, user1, user2):
|
||||
"""BFS to find shortest path"""
|
||||
if user1 == user2:
|
||||
return 0
|
||||
|
||||
visited = {user1}
|
||||
queue = deque([(user1, 0)])
|
||||
|
||||
while queue:
|
||||
current, degree = queue.popleft()
|
||||
|
||||
for friend in self.friends.get(current, []):
|
||||
if friend == user2:
|
||||
return degree + 1
|
||||
|
||||
if friend not in visited:
|
||||
visited.add(friend)
|
||||
queue.append((friend, degree + 1))
|
||||
|
||||
return -1 # Not connected
|
||||
```
|
||||
|
||||
## Tries (Prefix Trees)
|
||||
|
||||
**Use when:** Autocomplete, prefix matching, dictionary
|
||||
**Time:** O(m) for word length m
|
||||
**Space:** O(ALPHABET_SIZE * m * n)
|
||||
|
||||
### Common Patterns
|
||||
```python
|
||||
class TrieNode:
|
||||
def __init__(self):
|
||||
self.children = {}
|
||||
self.is_end = False
|
||||
|
||||
class Trie:
|
||||
def __init__(self):
|
||||
self.root = TrieNode()
|
||||
|
||||
def insert(self, word):
|
||||
node = self.root
|
||||
for char in word:
|
||||
if char not in node.children:
|
||||
node.children[char] = TrieNode()
|
||||
node = node.children[char]
|
||||
node.is_end = True
|
||||
|
||||
def search(self, word):
|
||||
node = self.root
|
||||
for char in word:
|
||||
if char not in node.children:
|
||||
return False
|
||||
node = node.children[char]
|
||||
return node.is_end
|
||||
|
||||
def starts_with(self, prefix):
|
||||
node = self.root
|
||||
for char in prefix:
|
||||
if char not in node.children:
|
||||
return False
|
||||
node = node.children[char]
|
||||
return True
|
||||
```
|
||||
|
||||
### Product Example: Google Search Autocomplete
|
||||
```python
|
||||
class Autocomplete:
|
||||
def __init__(self):
|
||||
self.trie = Trie()
|
||||
self.word_frequency = {}
|
||||
|
||||
def add_search(self, query):
|
||||
self.trie.insert(query)
|
||||
self.word_frequency[query] = \
|
||||
self.word_frequency.get(query, 0) + 1
|
||||
|
||||
def get_suggestions(self, prefix):
|
||||
suggestions = []
|
||||
|
||||
def dfs(node, current_word):
|
||||
if node.is_end:
|
||||
suggestions.append(current_word)
|
||||
|
||||
for char, child_node in node.children.items():
|
||||
dfs(child_node, current_word + char)
|
||||
|
||||
# Find prefix node
|
||||
node = self.trie.root
|
||||
for char in prefix:
|
||||
if char not in node.children:
|
||||
return []
|
||||
node = node.children[char]
|
||||
|
||||
# DFS from prefix node
|
||||
dfs(node, prefix)
|
||||
|
||||
# Sort by frequency
|
||||
return sorted(suggestions,
|
||||
key=lambda x: self.word_frequency.get(x, 0),
|
||||
reverse=True)[:5]
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Master these data structures with their common patterns:
|
||||
- Arrays: Two pointers, sliding window
|
||||
- Hash Maps: Frequency, caching
|
||||
- Linked Lists: Fast/slow pointers
|
||||
- Stacks: LIFO, parsing
|
||||
- Queues: FIFO, BFS
|
||||
- Heaps: Top K, priority
|
||||
- Trees: DFS, BFS
|
||||
- Graphs: Traversal, shortest path
|
||||
- Tries: Prefix operations
|
||||
|
||||
Each data structure has specific use cases - choose the right tool for the problem!
|
||||
469
skills/leetcode-teacher/references/patterns.md
Normal file
469
skills/leetcode-teacher/references/patterns.md
Normal file
@@ -0,0 +1,469 @@
|
||||
# LeetCode Patterns Reference
|
||||
|
||||
The 20 essential coding patterns for technical interviews with templates and real product examples.
|
||||
|
||||
## Pattern 1: Two Pointers
|
||||
|
||||
**When to Use:** Find pairs, triplets, or process sorted arrays
|
||||
**Time:** O(n), **Space:** O(1)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
def two_pointers(arr):
|
||||
left, right = 0, len(arr) - 1
|
||||
|
||||
while left < right:
|
||||
# Process current pair
|
||||
if condition:
|
||||
# Found solution
|
||||
return [left, right]
|
||||
elif arr[left] + arr[right] < target:
|
||||
left += 1
|
||||
else:
|
||||
right -= 1
|
||||
|
||||
return []
|
||||
```
|
||||
|
||||
### Real Example: Instagram Mutual Likes
|
||||
```python
|
||||
def find_mutual_likes(user_ids, target_sum):
|
||||
"""Find two users whose IDs sum to target"""
|
||||
left, right = 0, len(user_ids) - 1
|
||||
|
||||
while left < right:
|
||||
current_sum = user_ids[left] + user_ids[right]
|
||||
|
||||
if current_sum == target_sum:
|
||||
return [left, right]
|
||||
elif current_sum < target_sum:
|
||||
left += 1
|
||||
else:
|
||||
right -= 1
|
||||
|
||||
return []
|
||||
```
|
||||
|
||||
## Pattern 2: Sliding Window
|
||||
|
||||
**When to Use:** Find subarray/substring with property
|
||||
**Time:** O(n), **Space:** O(k)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
def sliding_window(arr, k):
|
||||
window_start = 0
|
||||
max_sum = 0
|
||||
window_sum = 0
|
||||
|
||||
for window_end in range(len(arr)):
|
||||
window_sum += arr[window_end]
|
||||
|
||||
if window_end >= k - 1:
|
||||
max_sum = max(max_sum, window_sum)
|
||||
window_sum -= arr[window_start]
|
||||
window_start += 1
|
||||
|
||||
return max_sum
|
||||
```
|
||||
|
||||
### Real Example: Twitter Trending Topics
|
||||
```python
|
||||
def trending_in_window(tweets, time_window):
|
||||
"""Find most mentioned hashtag in time window"""
|
||||
hashtag_count = {}
|
||||
max_count = 0
|
||||
trending = ""
|
||||
|
||||
for i, tweet in enumerate(tweets):
|
||||
# Add new tweet
|
||||
if tweet.hashtag in hashtag_count:
|
||||
hashtag_count[tweet.hashtag] += 1
|
||||
else:
|
||||
hashtag_count[tweet.hashtag] = 1
|
||||
|
||||
# Remove old tweets outside window
|
||||
if i >= time_window:
|
||||
old_tag = tweets[i - time_window].hashtag
|
||||
hashtag_count[old_tag] -= 1
|
||||
if hashtag_count[old_tag] == 0:
|
||||
del hashtag_count[old_tag]
|
||||
|
||||
# Track max
|
||||
for tag, count in hashtag_count.items():
|
||||
if count > max_count:
|
||||
max_count = count
|
||||
trending = tag
|
||||
|
||||
return trending
|
||||
```
|
||||
|
||||
## Pattern 3: Fast & Slow Pointers
|
||||
|
||||
**When to Use:** Detect cycles, find middle element
|
||||
**Time:** O(n), **Space:** O(1)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
def has_cycle(head):
|
||||
slow = fast = head
|
||||
|
||||
while fast and fast.next:
|
||||
slow = slow.next
|
||||
fast = fast.next.next
|
||||
|
||||
if slow == fast:
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
### Real Example: Package Manager Circular Dependency
|
||||
```python
|
||||
def detect_circular_dependency(package):
|
||||
"""Detect if package has circular dependencies"""
|
||||
slow = fast = package
|
||||
|
||||
while fast and fast.next_dependency:
|
||||
slow = slow.next_dependency
|
||||
fast = fast.next_dependency.next_dependency
|
||||
|
||||
if slow == fast:
|
||||
return True # Circular dependency found!
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
## Pattern 4: Merge Intervals
|
||||
|
||||
**When to Use:** Overlapping intervals, scheduling
|
||||
**Time:** O(n log n), **Space:** O(n)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
def merge_intervals(intervals):
|
||||
if not intervals:
|
||||
return []
|
||||
|
||||
intervals.sort(key=lambda x: x[0])
|
||||
merged = [intervals[0]]
|
||||
|
||||
for current in intervals[1:]:
|
||||
last = merged[-1]
|
||||
|
||||
if current[0] <= last[1]:
|
||||
# Overlapping, merge
|
||||
merged[-1] = [last[0], max(last[1], current[1])]
|
||||
else:
|
||||
# Non-overlapping
|
||||
merged.append(current)
|
||||
|
||||
return merged
|
||||
```
|
||||
|
||||
### Real Example: Google Calendar Free Slots
|
||||
```python
|
||||
def find_free_slots(calendars, duration):
|
||||
"""Find free meeting slots for all attendees"""
|
||||
# Merge all busy times
|
||||
busy = []
|
||||
for calendar in calendars:
|
||||
busy.extend(calendar.busy_times)
|
||||
|
||||
busy.sort()
|
||||
merged_busy = merge_intervals(busy)
|
||||
|
||||
# Find gaps >= duration
|
||||
free_slots = []
|
||||
for i in range(len(merged_busy) - 1):
|
||||
gap_start = merged_busy[i][1]
|
||||
gap_end = merged_busy[i + 1][0]
|
||||
|
||||
if gap_end - gap_start >= duration:
|
||||
free_slots.append([gap_start, gap_end])
|
||||
|
||||
return free_slots
|
||||
```
|
||||
|
||||
## Pattern 5: Binary Search (Modified)
|
||||
|
||||
**When to Use:** Search in O(log n), find boundary
|
||||
**Time:** O(log n), **Space:** O(1)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
def binary_search_modified(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
|
||||
```
|
||||
|
||||
### Real Example: GitHub Find Bug Introduction Version
|
||||
```python
|
||||
def find_first_bad_version(versions):
|
||||
"""Binary search to find when bug was introduced"""
|
||||
left, right = 0, len(versions) - 1
|
||||
first_bad = -1
|
||||
|
||||
while left <= right:
|
||||
mid = (left + right) // 2
|
||||
|
||||
if is_bad_version(versions[mid]):
|
||||
first_bad = mid
|
||||
right = mid - 1 # Look for earlier bad version
|
||||
else:
|
||||
left = mid + 1
|
||||
|
||||
return first_bad
|
||||
```
|
||||
|
||||
## Pattern 6: Top K Elements
|
||||
|
||||
**When to Use:** Find top/bottom K items
|
||||
**Time:** O(n log k), **Space:** O(k)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
import heapq
|
||||
|
||||
def top_k_elements(nums, k):
|
||||
# Min heap of size k
|
||||
min_heap = []
|
||||
|
||||
for num in nums:
|
||||
heapq.heappush(min_heap, num)
|
||||
|
||||
if len(min_heap) > k:
|
||||
heapq.heappop(min_heap)
|
||||
|
||||
return min_heap
|
||||
```
|
||||
|
||||
### Real Example: Reddit Top Posts
|
||||
```python
|
||||
def get_top_k_posts(posts, k):
|
||||
"""Get top K posts by upvotes"""
|
||||
min_heap = []
|
||||
|
||||
for post in posts:
|
||||
heapq.heappush(min_heap, (post.upvotes, post))
|
||||
|
||||
if len(min_heap) > k:
|
||||
heapq.heappop(min_heap)
|
||||
|
||||
return [post for (upvotes, post) in sorted(min_heap, reverse=True)]
|
||||
```
|
||||
|
||||
## Pattern 7: BFS (Breadth-First Search)
|
||||
|
||||
**When to Use:** Shortest path, level-order traversal
|
||||
**Time:** O(V + E), **Space:** O(V)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
def bfs(root):
|
||||
if not root:
|
||||
return []
|
||||
|
||||
result = []
|
||||
queue = deque([root])
|
||||
|
||||
while queue:
|
||||
level_size = len(queue)
|
||||
|
||||
for _ in range(level_size):
|
||||
node = queue.popleft()
|
||||
result.append(node.val)
|
||||
|
||||
if node.left:
|
||||
queue.append(node.left)
|
||||
if node.right:
|
||||
queue.append(node.right)
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
### Real Example: LinkedIn Degrees of Connection
|
||||
```python
|
||||
def degrees_of_connection(user1, user2):
|
||||
"""Find shortest connection path between users"""
|
||||
if user1 == user2:
|
||||
return 0
|
||||
|
||||
visited = {user1}
|
||||
queue = deque([(user1, 0)])
|
||||
|
||||
while queue:
|
||||
current_user, degree = queue.popleft()
|
||||
|
||||
for connection in current_user.connections:
|
||||
if connection == user2:
|
||||
return degree + 1
|
||||
|
||||
if connection not in visited:
|
||||
visited.add(connection)
|
||||
queue.append((connection, degree + 1))
|
||||
|
||||
return -1 # Not connected
|
||||
```
|
||||
|
||||
## Pattern 8: DFS (Depth-First Search)
|
||||
|
||||
**When to Use:** Path finding, backtracking
|
||||
**Time:** O(V + E), **Space:** O(V)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
def dfs(node, visited=None):
|
||||
if visited is None:
|
||||
visited = set()
|
||||
|
||||
if node in visited:
|
||||
return
|
||||
|
||||
visited.add(node)
|
||||
process(node)
|
||||
|
||||
for neighbor in node.neighbors:
|
||||
dfs(neighbor, visited)
|
||||
|
||||
return visited
|
||||
```
|
||||
|
||||
### Real Example: File System Path Finding
|
||||
```python
|
||||
def find_all_paths(start_dir, target_file):
|
||||
"""Find all paths to target file"""
|
||||
paths = []
|
||||
|
||||
def dfs(current_dir, path):
|
||||
if current_dir.name == target_file:
|
||||
paths.append(path + [current_dir.name])
|
||||
return
|
||||
|
||||
for subdir in current_dir.subdirectories:
|
||||
dfs(subdir, path + [current_dir.name])
|
||||
|
||||
dfs(start_dir, [])
|
||||
return paths
|
||||
```
|
||||
|
||||
## Pattern 9: Dynamic Programming
|
||||
|
||||
**When to Use:** Optimization, counting problems
|
||||
**Time:** Varies (often O(n²)), **Space:** O(n) or O(n²)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
def dp_solution(n):
|
||||
# Initialize DP array
|
||||
dp = [0] * (n + 1)
|
||||
dp[0] = base_case
|
||||
|
||||
# Fill DP array
|
||||
for i in range(1, n + 1):
|
||||
dp[i] = transition(dp[i-1], dp[i-2], ...)
|
||||
|
||||
return dp[n]
|
||||
```
|
||||
|
||||
### Real Example: Minimum Venmo Transactions
|
||||
```python
|
||||
def min_transactions(debts):
|
||||
"""Minimum transactions to settle all debts"""
|
||||
# Calculate net balance for each person
|
||||
balance = {}
|
||||
for payer, payee, amount in debts:
|
||||
balance[payer] = balance.get(payer, 0) - amount
|
||||
balance[payee] = balance.get(payee, 0) + amount
|
||||
|
||||
# Remove zero balances
|
||||
amounts = [v for v in balance.values() if v != 0]
|
||||
|
||||
def dfs(idx):
|
||||
# Skip settled accounts
|
||||
while idx < len(amounts) and amounts[idx] == 0:
|
||||
idx += 1
|
||||
|
||||
if idx == len(amounts):
|
||||
return 0
|
||||
|
||||
min_trans = float('inf')
|
||||
|
||||
for i in range(idx + 1, len(amounts)):
|
||||
# Try settling idx with i
|
||||
if amounts[idx] * amounts[i] < 0: # Different signs
|
||||
amounts[i] += amounts[idx]
|
||||
min_trans = min(min_trans, 1 + dfs(idx + 1))
|
||||
amounts[i] -= amounts[idx] # Backtrack
|
||||
|
||||
return min_trans
|
||||
|
||||
return dfs(0)
|
||||
```
|
||||
|
||||
## Pattern 10: Backtracking
|
||||
|
||||
**When to Use:** Generate all combinations, permutations
|
||||
**Time:** Exponential, **Space:** O(n)
|
||||
|
||||
### Template (Python)
|
||||
```python
|
||||
def backtrack(path, choices):
|
||||
if is_solution(path):
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
for choice in choices:
|
||||
# Make choice
|
||||
path.append(choice)
|
||||
|
||||
# Recurse
|
||||
backtrack(path, remaining_choices)
|
||||
|
||||
# Undo choice (backtrack)
|
||||
path.pop()
|
||||
```
|
||||
|
||||
### Real Example: Slack Channel Combinations
|
||||
```python
|
||||
def generate_team_combinations(members, team_size):
|
||||
"""Generate all possible teams of given size"""
|
||||
teams = []
|
||||
|
||||
def backtrack(start, current_team):
|
||||
if len(current_team) == team_size:
|
||||
teams.append(current_team[:])
|
||||
return
|
||||
|
||||
for i in range(start, len(members)):
|
||||
current_team.append(members[i])
|
||||
backtrack(i + 1, current_team)
|
||||
current_team.pop()
|
||||
|
||||
backtrack(0, [])
|
||||
return teams
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Master these 10 core patterns (plus 10 more in advanced practice) and you'll be able to solve 90%+ of LeetCode problems. Focus on:
|
||||
|
||||
1. **Recognition**: "I've seen this pattern before"
|
||||
2. **Template**: "I know the code structure"
|
||||
3. **Adaptation**: "I can modify for this specific problem"
|
||||
4. **Optimization**: "I can improve time/space complexity"
|
||||
|
||||
Practice each pattern 5-10 times until it becomes second nature!
|
||||
Reference in New Issue
Block a user