LeetCode 28: Find the Index of the First Occurrence in a String Solution in Python Explained

Problem Statement

Section link icon

LeetCode 28, Find the Index of the First Occurrence in a String, is an easy-level problem where you’re given two strings: haystack (the main string) and needle (the substring to find). Your task is to return the index of the first occurrence of needle in haystack, or -1 if needle isn’t found. The solution must not rely solely on built-in methods like find() or index() (though we’ll explore them as an alternative).

Constraints

  • 0 <= haystack.length, needle.length <= 10^4: Both strings’ lengths range from 0 to 10,000.
  • haystack and needle consist only of lowercase English characters.

Example

Input: haystack = "sadbutsad", needle = "sad"
Output: 0
Explanation: "sad" first occurs at index 0.

Input: haystack = "leetcode", needle = "leeto"
Output: -1
Explanation: "leeto" isn’t in "leetcode".

Input: haystack = "hello", needle = ""
Output: 0
Explanation: Empty needle returns 0 (start of string).

Understanding the Problem

Section link icon

How do you solve LeetCode 28: Find the Index of the First Occurrence in a String in Python? Given haystack = "sadbutsad" and needle = "sad", you need to find the first position where "sad" appears—here, index 0. If needle = "leeto" and haystack = "leetcode", return -1 since "leeto" isn’t present. We’ll explore two approaches: a Sliding Window Solution (optimal and primary) and an Alternative with Built-in Method (for comparison). The sliding window manually checks substrings, making it a great learning tool.

Solution 1: Sliding Window Approach (Primary)

Section link icon

Explanation

Use a sliding window of size len(needle) to scan haystack. At each position, compare the substring with needle. If they match, return the starting index; if no match is found after scanning, return -1.

Here’s a visual for haystack = "sadbutsad", needle = "sad":

Window 0: "sad" (match at 0)
Window 1: "adb" (no match)
...
Window 6: "sad" (match, but we return first: 0)
  1. Handle Edge Cases.
  • If needle is empty, return 0.
  • If needle is longer than haystack, return -1.
  1. Set Window Bounds.
  • Window size = len(needle).
  • Scan up to len(haystack) - len(needle) + 1.
  1. Slide and Compare.
  • Check each substring of haystack against needle.
  1. Return Result.
  • First match index or -1.

Step-by-Step Example

Example 1: haystack = "sadbutsad", needle = "sad"

We need the first occurrence at index 0.

  • Goal: Find first "sad" in "sadbutsad".
  • Result for Reference: 0.
  • Start: haystack = "sadbutsad", needle = "sad", len(needle) = 3.
  • Step 1: Check edge cases.
    • Needle not empty, len(haystack) = 9 ≥ len(needle) = 3, proceed.
  • Step 2: Window size = 3, scan up to 9 - 3 + 1 = 7.
  • Step 3: i = 0, substring = haystack[0:3] = "sad".
    • "sad" == "sad", match, return 0.
  • Step 4: (For completeness) i = 1, "adb" ≠ "sad", i = 2, "dbu" ≠ "sad", etc.
    • First match at 0 suffices.
  • Finish: Return 0.

Example 2: haystack = "leetcode", needle = "leeto"

We need -1 since "leeto" isn’t found.

  • Goal: Find first "leeto".
  • Result for Reference: -1.
  • Start: len(needle) = 5, len(haystack) = 8.
  • Step 1: Edge cases pass.
  • Step 2: Scan up to 8 - 5 + 1 = 4.
  • Step 3: i = 0, "leetc" ≠ "leeto".
  • Step 4: i = 1, "eetco" ≠ "leeto".
  • Step 5: i = 2, "etcod" ≠ "leeto".
  • Step 6: i = 3, "tcode" ≠ "leeto".
  • Step 7: No match, stop.
  • Finish: Return -1.

How the Code Works (Sliding Window)

Here’s the Python code with line-by-line explanation:

def strStr(haystack: str, needle: str) -> int:
    # Line 1: If needle is empty, return 0
    if not needle:
        return 0

    # Line 2: Lengths of haystack and needle
    n, m = len(haystack), len(needle)
    # Line 3: If needle longer than haystack, impossible
    if m > n:
        return -1

    # Line 4: Slide window up to n - m + 1
    for i in range(n - m + 1):
        # Line 5: Check substring against needle
        if haystack[i:i + m] == needle:
            # Line 6: Return first match index
            return i

    # Line 7: No match found
    return -1

Alternative: Built-in Method Approach

Section link icon

Explanation

Use Python’s find() method, which returns the first occurrence index or -1 if not found. While simple, LeetCode encourages understanding manual methods, so this is supplementary.

  1. Direct Call.
  • Call haystack.find(needle).
  1. Return Result.
  • Returns index or -1.

Step-by-Step Example (Alternative)

For haystack = "sadbutsad", needle = "sad":

  • Goal: Find first "sad".
  • Result for Reference: 0.
  • Step 1: Call "sadbutsad".find("sad").
  • Step 2: Returns 0 (first occurrence).
  • Finish: Return 0.

How the Code Works (Built-in)

def strStrBuiltIn(haystack: str, needle: str) -> int:
    # Line 1: Use find() to get first occurrence
    return haystack.find(needle)

Complexity

  • Sliding Window:
    • Time: O((n - m + 1) * m) – For each window position, compare m characters.
    • Space: O(1) – No extra space beyond substring comparison.
  • Built-in:
    • Time: O(n * m) – Internal implementation varies, typically similar to sliding window.
    • Space: O(1).

Efficiency Notes

The sliding window is O(n * m) in worst case (e.g., "aaaaa", "aa"), but it’s explicit and educational. Built-in find() is optimized but hides implementation details. For advanced efficiency, consider the KMP algorithm (O(n + m)), though it’s overkill for this problem.

Key Insights

Tips to master LeetCode 28:

  • Window Size Matters: Match it to needle length for accurate checks.
  • Edge Cases First: Empty needle or longer needle—handle these early!
  • Manual Beats Magic: Sliding window builds string-matching intuition.

Additional Example

Section link icon

For haystack = "mississippi", needle = "iss":

  • Goal: First "iss" at index 1.
  • Sliding Window: i = 0, "mis" ≠ "iss", i = 1, "iss" = "iss", return 1.
  • Result: 1.

Edge Cases

Section link icon
  • Empty Needle: haystack = "hello", needle = "" – Return 0.
  • Empty Haystack: haystack = "", needle = "a" – Return -1.
  • No Match: haystack = "abc", needle = "xyz" – Return -1.

Final Thoughts

Section link icon

The Sliding Window solution is perfect for LeetCode 28 in Python—clear, manual, and effective. For a related challenge, try LeetCode 27: Remove Element! Test it with tricky inputs like repeated patterns to sharpen your skills.