3083. Existence of a Substring in a String and Its Reverse
Problem Description
Given a string s
, find any substring of length 2
which is also present in the reverse of s
. Return true
if such a substring exists, and false
otherwise.
Intuition
To tackle this problem, consider the potential match between substrings of s
and its reverse. The solution leverages a set to store all possible contiguous pairs (substrings of length 2
) from the reverse of the string. By reversing s
, all pairs are examined in opposite order, facilitating the matching of each character from s
with its corresponding character in the reverse.
Next, iterate through the string and extract each pair (substring of length 2
). For each extracted pair, check against the previously stored pairs from the reversed string. If a match is found, it indicates the presence of a reverse order substring in the original string, and therefore, you return true
. If no matches are found by the end of the traversal, then return false
. This efficient approach ensures all necessary substrings are compared without redundancy.
Solution Approach
The solution utilizes a hash table to efficiently store and retrieve substrings. Here’s a detailed breakdown of the implementation:
-
Reverse the String: Begin by reversing the input string
s
. This is necessary to capture the substrings to be compared against substrings of the originals
. -
Extract Substrings from Reversed String: Using Python's set comprehension, create a set
st
that contains pairs (substrings of length2
) from the reversed string. This set ensures that only unique substrings are captured and allows for O(1) average-time complexity for membership checks.st = {(a, b) for a, b in pairwise(s[::-1])}
-
Check Substrings in the Original String: Traverse the original string
s
. For each contiguous pair (substring of length2
), check if this pair exists in the setst
.return any((a, b) in st for a, b in pairwise(s))
-
Return Result: If any such substring is found in both the original and reversed string’s substring set, return
true
. Otherwise, returnfalse
when the iteration completes without finding any such pairs.
This approach is efficient due to the use of a hash set and minimizes the complexity by ensuring each pair is only checked a single time.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Consider the string s = "abcda"
. Our task is to determine if there exists any substring of length 2
in s
that is also present in the reverse of s
.
-
Reverse the String:
- Reverse
s
to gets[::-1] = "adcba"
.
- Reverse
-
Extract Substrings from Reversed String:
- From
s[::-1] = "adcba"
, collect all substrings of length2
:- "ad", "dc", "cb", "ba".
- Store these in a set to avoid duplicates:
st = {"ad", "dc", "cb", "ba"}
.
- From
-
Check Substrings in the Original String:
- Traverse the original string
s
to find all substrings of length2
and check if they exist inst
. - Substrings in
s = "abcda"
are:- "ab", "bc", "cd", "da".
- Check each of these substrings against the set
st
:- "ab" is not in
st
. - "bc" is not in
st
. - "cd" is not in
st
. - "da" is in
st
.
- "ab" is not in
- Traverse the original string
-
Return Result:
- Since "da" is found in both the original string
s
and the setst
from the reversed string, the function returnstrue
.
- Since "da" is found in both the original string
This demonstrates that "da" exists as a substring in both s
and its reverse, satisfying the problem's conditions.
Solution Implementation
1from itertools import pairwise
2
3class Solution:
4 def isSubstringPresent(self, s: str) -> bool:
5 # Create a set of character pairs from the reversed string
6 reversed_pairs = {(first, second) for first, second in pairwise(s[::-1])}
7
8 # Check if any of the original string's character pairs are in the reversed set
9 return any((first, second) in reversed_pairs for first, second in pairwise(s))
10
1class Solution {
2 public boolean isSubstringPresent(String s) {
3 // Initialize a 2D boolean array representing pairs of consecutive characters
4 boolean[][] isPairPresent = new boolean[26][26];
5 int n = s.length();
6
7 // Populate the matrix to indicate the presence of a pair in the string
8 for (int i = 0; i < n - 1; ++i) {
9 // Mark the pair (s.charAt(i), s.charAt(i + 1)) as present
10 isPairPresent[s.charAt(i) - 'a'][s.charAt(i + 1) - 'a'] = true;
11 }
12
13 // Check if any marked pair reappears in the string
14 for (int i = 0; i < n - 1; ++i) {
15 // If the current pair (s.charAt(i), s.charAt(i + 1)) was marked earlier, return true
16 if (isPairPresent[s.charAt(i + 1) - 'a'][s.charAt(i) - 'a']) {
17 return true;
18 }
19 }
20
21 // Return false if no repeated pair is found
22 return false;
23 }
24}
25
1#include <string>
2using namespace std;
3
4class Solution {
5public:
6 bool isSubstringPresent(string s) {
7 // Declare and initialize a 2D array to store the presence of letter pairs.
8 bool charTransition[26][26] = {};
9
10 int n = s.size(); // Get the size of the input string.
11
12 // Iterate through the string to mark each pair of consecutive characters.
13 for (int i = 0; i < n - 1; ++i) {
14 charTransition[s[i + 1] - 'a'][s[i] - 'a'] = true;
15 }
16
17 // Check for each character pair if it exists in the previously filled data.
18 for (int i = 0; i < n - 1; ++i) {
19 if (charTransition[s[i] - 'a'][s[i + 1] - 'a']) {
20 // If any pair is found in the array, return true.
21 return true;
22 }
23 }
24
25 // If no pair is found, return false.
26 return false;
27 }
28};
29
1function isSubstringPresent(s: string): boolean {
2 // Create a 2D array to store the presence of substrings, initialized to false
3 const substringMatrix: boolean[][] = Array.from({ length: 26 }, () => Array(26).fill(false));
4
5 // Iterate through the string to populate the substringMatrix
6 for (let i = 0; i < s.length - 1; ++i) {
7 const currentCharIndex = s.charCodeAt(i) - 97;
8 const nextCharIndex = s.charCodeAt(i + 1) - 97;
9 substringMatrix[nextCharIndex][currentCharIndex] = true;
10 }
11
12 // Check for occurrences of any substring pattern in the matrix
13 for (let i = 0; i < s.length - 1; ++i) {
14 const currentCharIndex = s.charCodeAt(i) - 97;
15 const nextCharIndex = s.charCodeAt(i + 1) - 97;
16 if (substringMatrix[currentCharIndex][nextCharIndex]) {
17 return true;
18 }
19 }
20
21 // Return false if no such substring pattern exists
22 return false;
23}
24
Time and Space Complexity
-
Time Complexity: The
pairwise
function, if implemented optimally, will iterate over the strings
with a linear pass, making itO(n)
. Creating a set of pairs from the reversed string and checking existence in the set both requiren
operations, thus maintaining theO(n)
complexity. -
Space Complexity: The space complexity results from storing all pairs of adjacent characters in a set, which could theoretically grow to
O(|\Sigma|^2)
where\Sigma
represents the character set. For lowercase English letters,|\Sigma| = 26
, leading to a maximal space of storing26^2
distinct pairs.
Learn more about how to find time and space complexity quickly.
What's the output of running the following function using input [30, 20, 10, 100, 33, 12]
?
1def fun(arr: List[int]) -> List[int]:
2 import heapq
3 heapq.heapify(arr)
4 res = []
5 for i in range(3):
6 res.append(heapq.heappop(arr))
7 return res
8
1public static int[] fun(int[] arr) {
2 int[] res = new int[3];
3 PriorityQueue<Integer> heap = new PriorityQueue<>();
4 for (int i = 0; i < arr.length; i++) {
5 heap.add(arr[i]);
6 }
7 for (int i = 0; i < 3; i++) {
8 res[i] = heap.poll();
9 }
10 return res;
11}
12
1class HeapItem {
2 constructor(item, priority = item) {
3 this.item = item;
4 this.priority = priority;
5 }
6}
7
8class MinHeap {
9 constructor() {
10 this.heap = [];
11 }
12
13 push(node) {
14 // insert the new node at the end of the heap array
15 this.heap.push(node);
16 // find the correct position for the new node
17 this.bubble_up();
18 }
19
20 bubble_up() {
21 let index = this.heap.length - 1;
22
23 while (index > 0) {
24 const element = this.heap[index];
25 const parentIndex = Math.floor((index - 1) / 2);
26 const parent = this.heap[parentIndex];
27
28 if (parent.priority <= element.priority) break;
29 // if the parent is bigger than the child then swap the parent and child
30 this.heap[index] = parent;
31 this.heap[parentIndex] = element;
32 index = parentIndex;
33 }
34 }
35
36 pop() {
37 const min = this.heap[0];
38 this.heap[0] = this.heap[this.size() - 1];
39 this.heap.pop();
40 this.bubble_down();
41 return min;
42 }
43
44 bubble_down() {
45 let index = 0;
46 let min = index;
47 const n = this.heap.length;
48
49 while (index < n) {
50 const left = 2 * index + 1;
51 const right = left + 1;
52
53 if (left < n && this.heap[left].priority < this.heap[min].priority) {
54 min = left;
55 }
56 if (right < n && this.heap[right].priority < this.heap[min].priority) {
57 min = right;
58 }
59 if (min === index) break;
60 [this.heap[min], this.heap[index]] = [this.heap[index], this.heap[min]];
61 index = min;
62 }
63 }
64
65 peek() {
66 return this.heap[0];
67 }
68
69 size() {
70 return this.heap.length;
71 }
72}
73
74function fun(arr) {
75 const heap = new MinHeap();
76 for (const x of arr) {
77 heap.push(new HeapItem(x));
78 }
79 const res = [];
80 for (let i = 0; i < 3; i++) {
81 res.push(heap.pop().item);
82 }
83 return res;
84}
85
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!