Facebook Pixel

3083. Existence of a Substring in a String and Its Reverse

EasyHash TableString
Leetcode Link

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:

  1. Reverse the String: Begin by reversing the input string s. This is necessary to capture the substrings to be compared against substrings of the original s.

  2. Extract Substrings from Reversed String: Using Python's set comprehension, create a set st that contains pairs (substrings of length 2) 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])}
  3. Check Substrings in the Original String: Traverse the original string s. For each contiguous pair (substring of length 2), check if this pair exists in the set st.

    return any((a, b) in st for a, b in pairwise(s))
  4. Return Result: If any such substring is found in both the original and reversed string’s substring set, return true. Otherwise, return false 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 Evaluator

Example 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.

  1. Reverse the String:

    • Reverse s to get s[::-1] = "adcba".
  2. Extract Substrings from Reversed String:

    • From s[::-1] = "adcba", collect all substrings of length 2:
      • "ad", "dc", "cb", "ba".
    • Store these in a set to avoid duplicates:
      • st = {"ad", "dc", "cb", "ba"}.
  3. Check Substrings in the Original String:

    • Traverse the original string s to find all substrings of length 2 and check if they exist in st.
    • 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.
  4. Return Result:

    • Since "da" is found in both the original string s and the set st from the reversed string, the function returns true.

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 string s with a linear pass, making it O(n). Creating a set of pairs from the reversed string and checking existence in the set both require n operations, thus maintaining the O(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 storing 26^2 distinct pairs.

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

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

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More