questions C
This commit is contained in:
161
backend/data/questions/check-if-word-occurs-as-prefix.yaml
Normal file
161
backend/data/questions/check-if-word-occurs-as-prefix.yaml
Normal file
@@ -0,0 +1,161 @@
|
||||
title: Check If a Word Occurs As a Prefix of Any Word in a Sentence
|
||||
slug: check-if-word-occurs-as-prefix
|
||||
difficulty: easy
|
||||
leetcode_id: 1455
|
||||
leetcode_url: https://leetcode.com/problems/check-if-a-word-occurs-as-a-prefix-of-any-word-in-a-sentence/
|
||||
categories:
|
||||
- strings
|
||||
patterns:
|
||||
- two-pointers
|
||||
|
||||
description: |
|
||||
Given a `sentence` that consists of some words separated by a **single space**, and a `searchWord`, check if `searchWord` is a prefix of any word in `sentence`.
|
||||
|
||||
Return *the index of the word in* `sentence` *(**1-indexed**) where* `searchWord` *is a prefix of this word*. If `searchWord` is a prefix of more than one word, return the index of the first word **(minimum index)**. If there is no such word return `-1`.
|
||||
|
||||
A **prefix** of a string `s` is any leading contiguous substring of `s`.
|
||||
|
||||
constraints: |
|
||||
- `1 <= sentence.length <= 100`
|
||||
- `1 <= searchWord.length <= 10`
|
||||
- `sentence` consists of lowercase English letters and spaces.
|
||||
- `searchWord` consists of lowercase English letters.
|
||||
|
||||
examples:
|
||||
- input: 'sentence = "i love eating burger", searchWord = "burg"'
|
||||
output: "4"
|
||||
explanation: '"burg" is prefix of "burger" which is the 4th word in the sentence.'
|
||||
- input: 'sentence = "this problem is an easy problem", searchWord = "pro"'
|
||||
output: "2"
|
||||
explanation: '"pro" is prefix of "problem" which is the 2nd and the 6th word in the sentence, but we return 2 as it''s the minimal index.'
|
||||
- input: 'sentence = "i am tired", searchWord = "you"'
|
||||
output: "-1"
|
||||
explanation: '"you" is not a prefix of any word in the sentence.'
|
||||
|
||||
explanation:
|
||||
intuition: |
|
||||
Think of the sentence as a sequence of words laid out in a row, like books on a shelf. You're looking for the first book whose title *starts with* a specific set of letters.
|
||||
|
||||
The key insight is that we don't need any fancy string matching algorithms here. The problem is straightforward: split the sentence into individual words, then check each word one by one to see if it begins with `searchWord`.
|
||||
|
||||
Since we want the **first** matching word, we iterate through the words in order and return immediately when we find a match. This "early return" pattern is efficient because we stop as soon as we find what we're looking for.
|
||||
|
||||
The prefix check itself is simple: a word has `searchWord` as a prefix if the first `len(searchWord)` characters of the word exactly match `searchWord`. Most languages provide a built-in `startswith()` or similar method for this.
|
||||
|
||||
approach: |
|
||||
We solve this using a **Linear Scan with Prefix Check**:
|
||||
|
||||
**Step 1: Split the sentence into words**
|
||||
|
||||
- Use the space character as the delimiter to break the sentence into a list of words
|
||||
- This gives us direct access to each word by index
|
||||
|
||||
|
||||
|
||||
**Step 2: Iterate through words with their indices**
|
||||
|
||||
- For each word, check if it starts with `searchWord`
|
||||
- Python's `str.startswith()` method handles the prefix comparison efficiently
|
||||
- Remember the problem uses **1-indexed** positions, so we need to add 1 to the 0-based index
|
||||
|
||||
|
||||
|
||||
**Step 3: Return the result**
|
||||
|
||||
- If a word matches, return its 1-indexed position immediately
|
||||
- If no word matches after checking all, return `-1`
|
||||
|
||||
|
||||
|
||||
This approach works because we process words in order, guaranteeing we find the minimum index first.
|
||||
|
||||
common_pitfalls:
|
||||
- title: Off-by-One Error with 1-Indexing
|
||||
description: |
|
||||
The problem explicitly states that word positions are **1-indexed**, not 0-indexed. Many programming languages use 0-based indexing by default.
|
||||
|
||||
If you iterate with a loop like `for i in range(len(words))` and return `i` directly, you'll be off by one. The first word should return `1`, not `0`.
|
||||
|
||||
Always add 1 to convert from 0-indexed to 1-indexed, or use `enumerate(words, start=1)`.
|
||||
wrong_approach: "Returning 0-indexed position directly"
|
||||
correct_approach: "Add 1 to convert to 1-indexed position"
|
||||
|
||||
- title: Manual Prefix Checking Errors
|
||||
description: |
|
||||
If you implement prefix checking manually instead of using built-in methods, you might forget to check if the word is long enough.
|
||||
|
||||
For example, checking `word[:len(searchWord)] == searchWord` works, but manually comparing character-by-character without bounds checking could cause index out of range errors when the word is shorter than the search word.
|
||||
|
||||
Using `startswith()` handles all edge cases automatically.
|
||||
wrong_approach: "Manual character comparison without length check"
|
||||
correct_approach: "Use built-in startswith() or slice with length validation"
|
||||
|
||||
- title: Forgetting Empty String Edge Cases
|
||||
description: |
|
||||
While the constraints guarantee non-empty inputs, in a real interview you might encounter edge cases like empty sentences or empty search words.
|
||||
|
||||
An empty `searchWord` is technically a prefix of every word. Be prepared to discuss how you'd handle these cases if the constraints were relaxed.
|
||||
|
||||
key_takeaways:
|
||||
- "**Use built-in methods**: `startswith()` is cleaner and handles edge cases better than manual prefix checking"
|
||||
- "**Early return pattern**: Stop iterating as soon as you find the answer to avoid unnecessary work"
|
||||
- "**Watch for indexing conventions**: Problems often specify 1-indexed results when natural language is involved"
|
||||
- "**String splitting is your friend**: Converting a sentence to a word list simplifies iteration and access"
|
||||
|
||||
time_complexity: "O(n * m). We iterate through each character of the sentence once during split (O(n)), then for each word we may compare up to `m` characters where `m` is the length of `searchWord`. In the worst case, we check all words."
|
||||
space_complexity: "O(n). We store the list of words after splitting, which in the worst case contains all characters from the original sentence."
|
||||
|
||||
solutions:
|
||||
- approach_name: Linear Scan with startswith()
|
||||
is_optimal: true
|
||||
code: |
|
||||
def is_prefix_of_word(sentence: str, search_word: str) -> int:
|
||||
# Split sentence into list of words
|
||||
words = sentence.split()
|
||||
|
||||
# Check each word (enumerate with start=1 for 1-indexed result)
|
||||
for i, word in enumerate(words, start=1):
|
||||
# If this word starts with searchWord, return its position
|
||||
if word.startswith(search_word):
|
||||
return i
|
||||
|
||||
# No word had the prefix
|
||||
return -1
|
||||
explanation: |
|
||||
**Time Complexity:** O(n * m) — Where n is the sentence length and m is the search word length. Split is O(n), and each startswith check is O(m) in the worst case.
|
||||
|
||||
**Space Complexity:** O(n) — The words list stores all characters from the sentence.
|
||||
|
||||
This is the cleanest and most Pythonic solution. Using `enumerate` with `start=1` handles the 1-indexing requirement elegantly.
|
||||
|
||||
- approach_name: Manual Iteration Without Split
|
||||
is_optimal: false
|
||||
code: |
|
||||
def is_prefix_of_word(sentence: str, search_word: str) -> int:
|
||||
word_index = 1 # 1-indexed word counter
|
||||
word_start = 0 # Start position of current word
|
||||
|
||||
i = 0
|
||||
while i <= len(sentence):
|
||||
# End of word: either space or end of sentence
|
||||
if i == len(sentence) or sentence[i] == ' ':
|
||||
# Extract current word
|
||||
word = sentence[word_start:i]
|
||||
|
||||
# Check if searchWord is a prefix
|
||||
if word.startswith(search_word):
|
||||
return word_index
|
||||
|
||||
# Move to next word
|
||||
word_index += 1
|
||||
word_start = i + 1
|
||||
|
||||
i += 1
|
||||
|
||||
return -1
|
||||
explanation: |
|
||||
**Time Complexity:** O(n * m) — Same as the split approach.
|
||||
|
||||
**Space Complexity:** O(w) — Where w is the length of the longest word (for the substring extraction).
|
||||
|
||||
This approach avoids creating a list of all words upfront, potentially saving memory for very long sentences. However, it's more complex and the savings are negligible given the problem constraints.
|
||||
Reference in New Issue
Block a user