Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Build confidence with an intuition-first walkthrough focused on string matching fundamentals.
You are given a string s and a pattern string p, where p contains exactly one '*' character.
The '*' in p can be replaced with any sequence of zero or more characters.
Return true if p can be made a substring of s, and false otherwise.
Example 1:
Input: s = "leetcode", p = "ee*e"
Output: true
Explanation:
By replacing the '*' with "tcod", the substring "eetcode" matches the pattern.
Example 2:
Input: s = "car", p = "c*v"
Output: false
Explanation:
There is no substring matching the pattern.
Example 3:
Input: s = "luck", p = "u*"
Output: true
Explanation:
The substrings "u", "uc", and "uck" match the pattern.
Constraints:
1 <= s.length <= 501 <= p.length <= 50 s contains only lowercase English letters.p contains only lowercase English letters and exactly one '*'Problem summary: You are given a string s and a pattern string p, where p contains exactly one '*' character. The '*' in p can be replaced with any sequence of zero or more characters. Return true if p can be made a substring of s, and false otherwise.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: String Matching
"leetcode" "ee*e"
"car" "c*v"
"luck" "u*"
wildcard-matching)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3407: Substring Matching Pattern
class Solution {
public boolean hasMatch(String s, String p) {
int i = 0;
for (String t : p.split("\\*")) {
int j = s.indexOf(t, i);
if (j == -1) {
return false;
}
i = j + t.length();
}
return true;
}
}
// Accepted solution for LeetCode #3407: Substring Matching Pattern
func hasMatch(s string, p string) bool {
i := 0
for _, t := range strings.Split(p, "*") {
j := strings.Index(s[i:], t)
if j == -1 {
return false
}
i += j + len(t)
}
return true
}
# Accepted solution for LeetCode #3407: Substring Matching Pattern
class Solution:
def hasMatch(self, s: str, p: str) -> bool:
i = 0
for t in p.split("*"):
j = s.find(t, i)
if j == -1:
return False
i = j + len(t)
return True
// Accepted solution for LeetCode #3407: Substring Matching Pattern
impl Solution {
pub fn has_match(s: String, p: String) -> bool {
let mut i = 0usize;
for t in p.split('*') {
if let Some(j) = s[i..].find(t) {
i += j + t.len();
} else {
return false;
}
}
true
}
}
// Accepted solution for LeetCode #3407: Substring Matching Pattern
function hasMatch(s: string, p: string): boolean {
let i = 0;
for (const t of p.split('*')) {
const j = s.indexOf(t, i);
if (j === -1) {
return false;
}
i = j + t.length;
}
return true;
}
Use this to step through a reusable interview workflow for this problem.
At each of the n starting positions in the text, compare up to m characters with the pattern. If a mismatch occurs, shift by one and restart. Worst case (e.g., searching "aab" in "aaaa...a") checks m characters at nearly every position: O(n × m).
KMP and Z-algorithm preprocess the pattern in O(m) to build a failure/Z-array, then scan the text in O(n) — never backtracking. Total: O(n + m). Rabin-Karp uses rolling hashes for O(n + m) expected time. All beat the O(n × m) brute force of checking every position.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.