🚀 Introduction

Arrays (or lists in Python) and strings are among the most common data structures you’ll use. They form the backbone of many algorithms and interview questions.

In this post, we’ll explore:

✅ Python’s built-in list and string capabilities

✅ Essential algorithmic patterns: sliding window, two pointers, prefix sum

✅ Real-world problems and how to solve them

✅ Best practices and Pythonic shortcuts

📦 1️⃣ Python Lists: More Than Just Arrays

Python lists are dynamic arrays that can grow or shrink in size.

arr = [1, 2, 3]
arr.append(4)       # [1, 2, 3, 4]
arr.pop()           # [1, 2, 3]
arr.insert(1, 10)   # [1, 10, 2, 3]
del arr[0]          # [10, 2, 3]

🔹 List Slicing

nums = [1, 2, 3, 4, 5]
print(nums[1:4])     # [2, 3, 4]
print(nums[::-1])    # [5, 4, 3, 2, 1] – reversed

✅ Slicing is your best friend in array problems.

🔤 2️⃣ Strings in Python

Python strings are immutable and extremely versatile.

s = "hello"
print(s.upper())        # "HELLO"
print(s[1:4])           # "ell"
print("h" in s)         # True

🔹 String Tricks

# Reversing a string
reversed_s = s[::-1]

# Check for palindrome
def is_palindrome(s):
    return s == s[::-1]

🚦 3️⃣ Pattern: Two Pointers

Use two pointers to scan a list or string from both ends or at different speeds.

🔹 Example: Is a list a palindrome?

def is_palindrome(lst):
    left, right = 0, len(lst) - 1
    while left < right:
        if lst[left] != lst[right]:
            return False
        left += 1
        right -= 1
    return True

🔹 Example: Remove Duplicates from Sorted Array

def remove_duplicates(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

✅ Use when you need to compare or update positions in-place.

🔍 4️⃣ Pattern: Sliding Window

Efficiently track values over a moving range.

🔹 Example: Max sum of subarray of size k

def max_subarray_sum(nums, k):
    window_sum = sum(nums[:k])
    max_sum = window_sum
    for i in range(k, len(nums)):
        window_sum += nums[i] - nums[i - k]
        max_sum = max(max_sum, window_sum)
    return max_sum

✅ Use when dealing with contiguous sequences like subarrays, substrings, etc.

➕ 5️⃣ Pattern: Prefix Sum

Prefix sum helps in range sum queries and cumulative processing.

🔹 Example: Range sum query

def prefix_sum(nums):
    prefix = [0]
    for num in nums:
        prefix.append(prefix[-1] + num)
    return prefix

# Sum of elements from index i to j: prefix[j+1] - prefix[i]

✅ Reduces repeated computation in range-based problems.

🧪 6️⃣ Practice Problems

Problem Pattern Tip
Two Sum Hashing / Two Pointers Use a set for complements
Maximum Subarray Kadane’s Algorithm Track max ending at current index
Longest Substring Without Repeating Characters Sliding Window Use a set or dict for seen chars
Palindrome Check Two Pointers Compare left and right
Product of Array Except Self Prefix & Suffix Arrays Avoid division

✅ Best Practices

✔️ Know when to use in-place operations to save space
✔️ Use enumerate() to loop with index
✔️ Avoid += on strings in loops (use ''.join() instead)
✔️ Leverage collections.Counter, set, and defaultdict for advanced use cases
❌ Avoid nested loops unless necessary — try sliding window or hashing

🧠 Summary

✔️ Lists and strings are the foundation of most coding problems
✔️ Learn and practice patterns like two pointers, sliding window, and prefix sums
✔️ Python’s expressive syntax helps solve these problems cleanly and concisely
✔️ Build your DSA muscle memory with hands-on problems using these patterns

🔜 Coming Up Next:

👉 Part 3: Stacks and Queues – Theory, Python Implementations, and Interview Classics

We’ll explore:

  1. Real-world uses of stacks & queues
  2. How to implement with Python lists and deque
  3. Problems like parentheses validation, undo/redo, and level-order traversal

💬 Got a favorite array/string trick? Or stuck on a pattern? Drop a comment and let’s chat! 🧩🔥