📘 Week 1: Mastering Arrays, Hash Maps, and Problem-Solving Patterns

Table of contents
- 📘 Data Structures
- 🧠 Problem Solving Patterns & Techniques
- ✅ 1. Kadane’s Algorithm – Maximum Subarray Sum
- ✅ 2. Two Pointer Technique – Remove Duplicates
- ✅ 3. Sliding Window – Maximize Window
- ✅ 4. Dutch National Flag – Sort 0s, 1s, 2s
- ✅ 5. Recursion Basics
- ✅ 6. Prefix Sum
- ✅ 7. Sorting Techniques Summary
- ✅ 1. Bubble Sort
- 🔍 Intuition:
- 📑 Algorithm:
- 🧠 Complexity:
- ✅ Code:
- ✅ 2. Selection Sort
- 🔍 Intuition:
- 📑 Algorithm:
- 🧠 Complexity:
- ✅ Code:
- ✅ 3. Insertion Sort
- 🔍 Intuition:
- 📑 Algorithm:
- 🧠 Complexity:
- ✅ Code:
- ✅ 4. Merge Sort (Optimal)
- 🔍 Intuition:
- 📑 Algorithm:
- 🧠 Complexity:
- ✅ Code:
- ✅ 5. Quick Sort (Optimal, In-Place)
- 🔍 Intuition:
- 📑 Algorithm:
- 🧠 Complexity:
- ✅ Code:
- ✅ 8. Matrix Traversals & Rotation
- ✅ Summary

Welcome to Week 1 of your DSA journey! This week focuses on building a strong foundation by mastering arrays, 2D matrices, hash maps, and recursion, along with 10 essential problem-solving patterns that will keep recurring throughout your DSA prep.
📘 Data Structures
1. Array
Arrays are the most basic and foundational data structure in programming. They are used to store elements in a contiguous block of memory, allowing constant-time access via index.
💡 Key Use Cases:
Traversal
Sorting
Rotating or reversing
Subarray computations (e.g., Kadane’s Algorithm)
Dutch National Flag problem
✅ Example 1: Best Time to Buy and Sell Stock (LeetCode 121)
def maxProfit(prices):
min_price = float('inf')
max_profit = 0
for price in prices:
min_price = min(min_price, price)
max_profit = max(max_profit, price - min_price)
return max_profit
✅ Example 2: Maximum Subarray using Kadane’s Algorithm (LeetCode 53)
def maxSubArray(nums):
max_sum = curr_sum = nums[0]
for num in nums[1:]:
curr_sum = max(num, curr_sum + num)
max_sum = max(max_sum, curr_sum)
return max_sum
2. 2D Array / Matrix
Matrices extend arrays into 2 dimensions, enabling grid-based computations such as image rotation, dynamic programming, and more.
💡 Key Use Cases:
Matrix traversal
Spiral order traversal
Setting rows/columns to zero
Rotating matrix in place
✅ Example: Set Matrix Zeroes (LeetCode 73)
def setZeroes(matrix):
rows, cols = len(matrix), len(matrix[0])
row_set, col_set = set(), set()
for i in range(rows):
for j in range(cols):
if matrix[i][j] == 0:
row_set.add(i)
col_set.add(j)
for i in range(rows):
for j in range(cols):
if i in row_set or j in col_set:
matrix[i][j] = 0
3. Hash Map (Python dict)
A hash map (dictionary in Python) allows for constant time insertions, deletions, and lookups using key-value pairs.
💡 Key Use Cases:
Frequency counting
2Sum problems
Prefix sum indexing
✅ Example: Two Sum (LeetCode 1)
def twoSum(nums, target):
seen = {}
for i, num in enumerate(nums):
diff = target - num
if diff in seen:
return [seen[diff], i]
seen[num] = i
4. Recursion Stack
Though not explicitly a data structure, recursion uses the call stack to store execution state. It’s especially useful for problems with self-similar structure (e.g. trees, backtracking).
✅ Example: Print Numbers from 1 to N
def printNums(n):
if n == 0:
return
printNums(n - 1)
print(n)
🧠 Problem Solving Patterns & Techniques
✅ 1. Kadane’s Algorithm – Maximum Subarray Sum
🔍 Problem:
Find the contiguous subarray with the maximum sum.
📑 Steps:
Initialize
current_sum
andmax_sum
to first elementIterate through the array
At each step, choose:
current_sum = max(num, current_sum + num)
Update
max_sum
as the maximum of itself andcurrent_sum
Return
max_sum
🧮 Dry Run:
Input: [-2,1,-3,4,-1,2,1,-5,4]
Max Subarray: [4,-1,2,1]
→ Sum = 6
✅ Code:
def maxSubArray(nums):
current_sum = max_sum = nums[0]
for num in nums[1:]:
current_sum = max(num, current_sum + num)
max_sum = max(max_sum, current_sum)
return max_sum
✅ 2. Two Pointer Technique – Remove Duplicates
🔍 Problem:
Remove duplicates from a sorted array in-place.
📑 Steps:
Set
i = 0
,j = 1
While
j < len(nums)
:If
nums[i] != nums[j]
: incrementi
, setnums[i] = nums[j]
Always move
j
forward
Return
i + 1
(length of unique array)
✅ Code:
def removeDuplicates(nums):
if not nums:
return 0
i = 0
for j in range(1, len(nums)):
if nums[j] != nums[i]:
i += 1
nums[i] = nums[j]
return i + 1
✅ 3. Sliding Window – Maximize Window
🔍 Problem:
Find longest subarray with at most k
zero flips
📑 Steps:
Initialize
left = 0
Move
right
through arrayIf
nums[right] == 0
, reducek
If
k < 0
, moveleft
forward and increasek
if left element was 0Track window length with
right - left + 1
✅ Code:
def longestOnes(nums, k):
left = 0
for right in range(len(nums)):
if nums[right] == 0:
k -= 1
if k < 0:
if nums[left] == 0:
k += 1
left += 1
return right - left + 1
✅ 4. Dutch National Flag – Sort 0s, 1s, 2s
📑 Steps:
Initialize:
low = mid = 0
,high = len(nums) - 1
While
mid <= high
:If
nums[mid] == 0
: swap withlow
, increment bothIf
nums[mid] == 1
: movemid
If
nums[mid] == 2
: swap withhigh
, decrementhigh
✅ Code:
def sortColors(nums):
low = mid = 0
high = len(nums) - 1
while mid <= high:
if nums[mid] == 0:
nums[low], nums[mid] = nums[mid], nums[low]
low += 1
mid += 1
elif nums[mid] == 1:
mid += 1
else:
nums[mid], nums[high] = nums[high], nums[mid]
high -= 1
✅ 5. Recursion Basics
📑 Steps:
Define base case (e.g.,
if n == 0
)Make recursive call with smaller input
Do work before/after the call as needed
✅ Fibonacci Recursion:
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
✅ 6. Prefix Sum
📑 Steps:
Initialize prefix list:
prefix = [0]
Loop through array, build
prefix[i+1] = prefix[i] + arr[i]
Range sum:
prefix[j+1] - prefix[i]
✅ Code:
def computePrefix(nums):
prefix = [0]
for num in nums:
prefix.append(prefix[-1] + num)
return prefix
✅ 7. Sorting Techniques Summary
Algorithm | Time Complexity | Stable | Use Case |
Bubble Sort | O(n^2) | Yes | Educational only |
Selection Sort | O(n^2) | No | Small inputs |
Insertion Sort | O(n^2) | Yes | Nearly sorted arrays |
Merge Sort | O(n log n) | Yes | Guaranteed performance |
Quick Sort | O(n log n) avg | No | Fast and practical |
✅ 1. Bubble Sort
🔍 Intuition:
Repeatedly swap adjacent elements if they are in the wrong order. "Bubble up" the largest element to the end in each pass.
📑 Algorithm:
For every
i
from0
ton-1
:- For every
j
from0
ton-i-2
, ifarr[j] > arr[j+1]
, swap them.
- For every
Repeat until no swaps are needed.
🧠 Complexity:
Time: O(n²)
Space: O(1)
Stable: ✅ Yes
✅ Code:
pythonCopyEditdef bubbleSort(arr):
n = len(arr)
for i in range(n):
swapped = False
for j in range(0, n - 1 - i):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
swapped = True
if not swapped:
break
✅ 2. Selection Sort
🔍 Intuition:
Select the minimum element in the unsorted part and place it at the beginning.
📑 Algorithm:
Loop
i
from0
ton-1
Find index
min_idx
of the smallest element fromi
ton-1
Swap
arr[i]
andarr[min_idx]
🧠 Complexity:
Time: O(n²)
Space: O(1)
Stable: ❌ No
✅ Code:
pythonCopyEditdef selectionSort(arr):
n = len(arr)
for i in range(n):
min_idx = i
for j in range(i + 1, n):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
✅ 3. Insertion Sort
🔍 Intuition:
Insert each element into its correct position in the sorted portion on the left.
📑 Algorithm:
Loop
i
from1
ton-1
Store
key = arr[i]
, and shift all greater elements one position rightPlace
key
in its correct sorted position
🧠 Complexity:
Time: O(n²), but O(n) best case (already sorted)
Space: O(1)
Stable: ✅ Yes
✅ Code:
pythonCopyEditdef insertionSort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
✅ 4. Merge Sort (Optimal)
🔍 Intuition:
Divide the array into halves, recursively sort, then merge.
📑 Algorithm:
Divide array until size = 1
Merge two sorted arrays into one
🧠 Complexity:
Time: O(n log n)
Space: O(n)
Stable: ✅ Yes
✅ Code:
pythonCopyEditdef mergeSort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = mergeSort(arr[:mid])
right = mergeSort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
✅ 5. Quick Sort (Optimal, In-Place)
🔍 Intuition:
Pick a pivot, partition array around it, then sort partitions recursively.
📑 Algorithm:
Choose pivot (typically last element)
Partition: place all elements smaller than pivot to left, greater to right
Recursively quick sort left and right partitions
🧠 Complexity:
Time: O(n log n) average, O(n²) worst
Space: O(log n)
Stable: ❌ No
✅ Code:
pythonCopyEditdef quickSort(arr, low, high):
if low < high:
pi = partition(arr, low, high)
quickSort(arr, low, pi - 1)
quickSort(arr, pi + 1, high)
def partition(arr, low, high):
pivot = arr[high]
i = low - 1
for j in range(low, high):
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]
arr[i+1], arr[high] = arr[high], arr[i+1]
return i + 1
✅ 8. Matrix Traversals & Rotation
🔁 Spiral Traversal Steps:
Top row → Right col → Bottom row → Left col
Shrink boundaries, repeat
def spiralOrder(matrix):
result = []
top, bottom = 0, len(matrix)
left, right = 0, len(matrix[0])
while top < bottom and left < right:
for i in range(left, right):
result.append(matrix[top][i])
top += 1
for i in range(top, bottom):
result.append(matrix[i][right - 1])
right -= 1
if top < bottom:
for i in range(right - 1, left - 1, -1):
result.append(matrix[bottom - 1][i])
bottom -= 1
if left < right:
for i in range(bottom - 1, top - 1, -1):
result.append(matrix[i][left])
left += 1
return result
🔁 Rotate Matrix 90° Clockwise:
Transpose matrix (swap i, j)
Reverse each row
def rotate(matrix):
n = len(matrix)
for i in range(n):
for j in range(i, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
for row in matrix:
row.reverse()
✅ Summary
📦 Data Structures
Data Structure | Key Use Cases | Example Problems |
Array | Traversal, sorting, reversing, subarrays, Kadane’s, Dutch National Flag | - 121. Best Time to Buy and Sell Stock |
- 53. Maximum Subarray | ||
2D Array / Matrix | Rotation (90°), spiral print, set matrix zeros | - 73. Set Matrix Zeroes |
Hash Map (Python dict ) | Frequency count, prefix sums, complements (2Sum), subarray sums | - 1. Two Sum |
Recursion Stack | Implicit stack via function calls for divide-and-conquer, backtracking, printing patterns | - Print 1 to N (custom) |
- 509. Fibonacci Number |
🧠 Problem-Solving Patterns & Techniques
Pattern | Key Idea / Use Case | Example Problems |
✅ Kadane’s Algorithm | Find max subarray sum in O(n) | - 53. Maximum Subarray |
✅ Two Pointers | Move two indices with different purposes (fast/slow, start/end) | - 26. Remove Duplicates from Sorted Array |
✅ Sliding Window | Fixed or dynamic window to handle subarrays | - 1004. Max Consecutive Ones III |
✅ Prefix Sum | Precompute running sum to optimize subarray queries | - Custom implementation for subarray sum |
✅ Dutch National Flag Algorithm | Sort 0s, 1s, 2s in a single pass using 3 pointers | - 75. Sort Colors |
✅ Recursion Basics | Function calling itself with a base case | - 509. Fibonacci Number |
✅ Sorting Techniques | Learn Bubble, Selection, Insertion, Merge, Quick Sort | - 912. Sort an Array |
✅ Matrix Traversals | Layer-wise spiral or rotation | - 48. Rotate Image |
✍️ Stay consistent. Solve, analyze, and blog your learnings!
Subscribe to my newsletter
Read articles from Shashank Ghosh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Shashank Ghosh
Shashank Ghosh
AI/ML Developer in the making | Solving DSA with Striver’s A2Z Sheet | Blogging weekly to stay consistent and teach what I learn.