Given a pattern string pat and a text string txt, check if pattern matches according to the following rules:
- If pat is preceded by a ^, the pattern is matched against the starting position of txt, excluding the ^.
- If pat is succeeded by a $, the pattern is matched against the ending position of txt.
- If neither marker is present, check whether pat is a substring of txt.
- If both markers are present, then both the starting and ending positions are matched.
Return true if pat matches txt according to the above rules, otherwise return false.
Examples:
Input: pat = "^coal", txt = "coaltar"
Output: true
Explanation: The pattern "coal" is present at the beginning of the string, so the output is true.Input: pat = "tar$", txt = "coaltar"
Output: true
Explanation: The pattern "tar" (with the $ marker removed) matches the ending position of txt, so the output is true.Input: pat = "^a$", txt = "aba"
Output: true
Explanation: The pattern "a" (with both ^ and $ markers removed) matches both the starting and ending positions of txt, so the output is true.
Try It Yourself
Using KMP Search - O(|txt| + |pat|) Time and O(|pat|) Space
- If ^ is present at the beginning, compare it with prefix of txt
- If $ is present at the end of pat, compare it with suffix of txt
- If both are not present, use KMP to search.
Illustration:
- Take pat = "^coal", txt = "coaltar".
- pat starts with ^ and does not end with $, so only the start-anchored case applies.
- The core pattern (with ^ removed) is "coal".
- Checking whether txt starts with "coal": txt = "coaltar", and its first 4 characters are exactly "coal", so this matches.
- Since the prefix matches, the result is true.
#include <bits/stdc++.h>
using namespace std;
// builds the longest-prefix-suffix array used by
// KMP to skip redundant comparisons
vector<int> buildLps(string &pat) {
int n = pat.length();
vector<int> lps(n, 0);
int length = 0;
int i = 1;
while (i < n) {
if (pat[i] == pat[length]) {
length++;
lps[i] = length;
i++;
} else {
if (length!= 0) {
length = lps[length - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
// searches for pat as a substring of txt using KMP,
// avoiding re-scanning matched characters
bool kmpSearch(string &txt, string &pat) {
int n = txt.length(), m = pat.length();
if (m > n)
return false;
vector<int> lps = buildLps(pat);
int i = 0, j = 0;
while (i < n) {
if (txt[i] == pat[j]) {
i++;
j++;
if (j == m)
return true;
} else {
if (j!= 0) {
j = lps[j - 1];
} else {
i++;
}
}
}
return false;
}
bool isPatternPresent(string &txt, string &pat) {
// pattern anchored at both start and end: core must match both the prefix
// and suffix of txt independently, extra characters in between are ignored
if (pat.size() >= 2 && pat[0] == '^' && pat.back() == '$') {
string core = pat.substr(1, pat.size() - 2);
if (core.size() > txt.size())
return false;
return txt.substr(0, core.size()) == core &&
txt.substr(txt.size() - core.size()) == core;
}
// pattern anchored at the start only
else if (pat[0] == '^') {
string core = pat.substr(1);
if (core.size() > txt.size())
return false;
return txt.substr(0, core.size()) == core;
}
// pattern anchored at the end only
else if (pat.back() == '$') {
string core = pat.substr(0, pat.size() - 1);
if (core.size() > txt.size())
return false;
return txt.substr(txt.size() - core.size()) == core;
}
// no anchors, search as a plain substring using KMP for better time complexity
else {
return kmpSearch(txt, pat);
}
}
int main() {
string pat = "^coal", txt = "coaltar";
cout << boolalpha << isPatternPresent(txt, pat) << endl;
return 0;
}
class GFG {
// builds the longest-prefix-suffix array
// used by KMP to skip redundant comparisons
static int[] buildLps(String pat) {
int n = pat.length();
int[] lps = new int[n];
int length = 0;
int i = 1;
while (i < n) {
if (pat.charAt(i) == pat.charAt(length)) {
length++;
lps[i] = length;
i++;
} else {
if (length != 0) {
length = lps[length - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
// searches for pat as a substring of txt using KMP,
// avoiding re-scanning matched characters
static boolean kmpSearch(String txt, String pat) {
int n = txt.length(), m = pat.length();
if (m > n)
return false;
int[] lps = buildLps(pat);
int i = 0, j = 0;
while (i < n) {
if (txt.charAt(i) == pat.charAt(j)) {
i++;
j++;
if (j == m)
return true;
} else {
if (j != 0) {
j = lps[j - 1];
} else {
i++;
}
}
}
return false;
}
static boolean isPatternPresent(String txt, String pat) {
// pattern anchored at both start and end: core must
// match both the prefix and suffix of txt independently,
// extra characters in between are ignored
if (pat.length() >= 2 && pat.charAt(0) == '^' && pat.charAt(pat.length() - 1) == '$') {
String core = pat.substring(1, pat.length() - 1);
if (core.length() > txt.length())
return false;
return txt.substring(0, core.length()).equals(core) &&
txt.substring(txt.length() - core.length()).equals(core);
}
// pattern anchored at the start only
else if (pat.charAt(0) == '^') {
String core = pat.substring(1);
if (core.length() > txt.length())
return false;
return txt.substring(0, core.length()).equals(core);
}
// pattern anchored at the end only
else if (pat.charAt(pat.length() - 1) == '$') {
String core = pat.substring(0, pat.length() - 1);
if (core.length() > txt.length())
return false;
return txt.substring(txt.length() - core.length()).equals(core);
}
// no anchors, search as a plain substring using KMP
// for better time complexity
else {
return kmpSearch(txt, pat);
}
}
public static void main(String[] args) {
String pat = "^coal", txt = "coaltar";
System.out.println(isPatternPresent(txt, pat));
}
}
def buildLps(pat):
# builds the longest-prefix-suffix array used by
# KMP to skip redundant comparisons
n = len(pat)
lps = [0] * n
length = 0
i = 1
while i < n:
if pat[i] == pat[length]:
length += 1
lps[i] = length
i += 1
else:
if length != 0:
length = lps[length - 1]
else:
lps[i] = 0
i += 1
return lps
def kmpSearch(txt, pat):
# searches for pat as a substring of txt using KMP,
# avoiding re-scanning matched characters
n, m = len(txt), len(pat)
if m > n:
return False
lps = buildLps(pat)
i = j = 0
while i < n:
if txt[i] == pat[j]:
i += 1
j += 1
if j == m:
return True
else:
if j != 0:
j = lps[j - 1]
else:
i += 1
return False
def isPatternPresent(txt, pat):
# pattern anchored at both start and end: core
# must match both the prefix and suffix of txt
# independently, extra characters in between are ignored
if len(pat) >= 2 and pat[0] == '^' and pat[-1] == '$':
core = pat[1:-1]
if len(core) > len(txt):
return False
return txt[:len(core)] == core and txt[-len(core):] == core
# pattern anchored at the start only
elif pat[0] == '^':
core = pat[1:]
if len(core) > len(txt):
return False
return txt[:len(core)] == core
# pattern anchored at the end only
elif pat[-1] == '$':
core = pat[:-1]
if len(core) > len(txt):
return False
return txt[-len(core):] == core
# no anchors, search as a plain substring using KMP
# for better time complexity
else:
return kmpSearch(txt, pat)
pat = "^coal"
txt = "coaltar"
print(isPatternPresent(txt, pat))
using System;
class GFG {
// builds the longest-prefix-suffix array used
// by KMP to skip redundant comparisons
static int[] buildLps(string pat) {
int n = pat.Length;
int[] lps = new int[n];
int length = 0;
int i = 1;
while (i < n) {
if (pat[i] == pat[length]) {
length++;
lps[i] = length;
i++;
} else {
if (length != 0) {
length = lps[length - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
// searches for pat as a substring of txt using KMP,
// avoiding re-scanning matched characters
static bool kmpSearch(string txt, string pat) {
int n = txt.Length, m = pat.Length;
if (m > n)
return false;
int[] lps = buildLps(pat);
int i = 0, j = 0;
while (i < n) {
if (txt[i] == pat[j]) {
i++;
j++;
if (j == m)
return true;
} else {
if (j != 0) {
j = lps[j - 1];
} else {
i++;
}
}
}
return false;
}
static bool isPatternPresent(string txt, string pat) {
// pattern anchored at both start and end: core
// must match both the prefix and suffix of txt
// independently, extra characters in between are ignored
if (pat.Length >= 2 && pat[0] == '^' && pat[pat.Length - 1] == '$') {
string core = pat.Substring(1, pat.Length - 2);
if (core.Length > txt.Length)
return false;
return txt.Substring(0, core.Length) == core &&
txt.Substring(txt.Length - core.Length) == core;
}
// pattern anchored at the start only
else if (pat[0] == '^') {
string core = pat.Substring(1);
if (core.Length > txt.Length)
return false;
return txt.Substring(0, core.Length) == core;
}
// pattern anchored at the end only
else if (pat[pat.Length - 1] == '$') {
string core = pat.Substring(0, pat.Length - 1);
if (core.Length > txt.Length)
return false;
return txt.Substring(txt.Length - core.Length) == core;
}
// no anchors, search as a plain substring using
// KMP for better time complexity
else {
return kmpSearch(txt, pat);
}
}
static void Main() {
string pat = "^coal", txt = "coaltar";
Console.WriteLine(isPatternPresent(txt, pat));
}
}
// builds the longest-prefix-suffix array used
// by KMP to skip redundant comparisons
function buildLps(pat) {
const n = pat.length;
const lps = new Array(n).fill(0);
let length = 0;
let i = 1;
while (i < n) {
if (pat[i] === pat[length]) {
length++;
lps[i] = length;
i++;
} else {
if (length !== 0) {
length = lps[length - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
// searches for pat as a substring of txt using KMP,
// avoiding re-scanning matched characters
function kmpSearch(txt, pat) {
const n = txt.length, m = pat.length;
if (m > n)
return false;
const lps = buildLps(pat);
let i = 0, j = 0;
while (i < n) {
if (txt[i] === pat[j]) {
i++;
j++;
if (j === m)
return true;
} else {
if (j !== 0) {
j = lps[j - 1];
} else {
i++;
}
}
}
return false;
}
function isPatternPresent(txt, pat) {
// pattern anchored at both start and end: core
// must match both the prefix and suffix of txt
// independently, extra characters in between are ignored
if (pat.length >= 2 && pat[0] === '^' && pat[pat.length - 1] === '$') {
const core = pat.slice(1, -1);
if (core.length > txt.length)
return false;
return txt.slice(0, core.length) === core &&
txt.slice(txt.length - core.length) === core;
}
// pattern anchored at the start only
else if (pat[0] === '^') {
const core = pat.slice(1);
if (core.length > txt.length)
return false;
return txt.slice(0, core.length) === core;
}
// pattern anchored at the end only
else if (pat[pat.length - 1] === '$') {
const core = pat.slice(0, -1);
if (core.length > txt.length)
return false;
return txt.slice(txt.length - core.length) === core;
}
// no anchors, search as a plain substring using
// KMP for better time complexity
else {
return kmpSearch(txt, pat);
}
}
// Driver Code
const pat = "^coal", txt = "coaltar";
console.log(isPatternPresent(txt, pat));
Output
true