Perfect Reversible String in JavaScript
A string is said to be a perfectly reversible string when the reverse of all the possible substrings of the string is available or present in the string. In this article, we are going to check whether a string is a perfectly reversible string or not in JavaScript with the help of practical implementation and code examples.
Examples:
Input: string = "xyz"
Output: "No"
Explanation: All possible sub strings: 'x', 'y', 'z', 'xy', 'yz', 'xyz'.
Here the reverse of sub strings 'xy', 'yz' and 'xyz' is not avaialable.
Hence, it returns No as output.
Input: string = "xyx"
Output: "Yes"
Explanation: All possible sub strings: 'x', 'y', 'x', 'xy', 'yx', 'xyx'.
Here the reverse of all the sub strings is available.
Hence, it returns Yes as output.
There are two approaches available to solve this question:
Table of Content
Naive Approach
In the naive or simple approach, we will first find out all the substrings of the provided string and store them in an array. After getting the substrings, we will check whether the reverse of all the substrings is the same as the substring or not, and according to the checked condition, the result will be shown to the user on the output screen.
Example: This code example will help you understand whether a string is perfectly reversible or not in JavaScript:
function isRevPer(str) {
// Creating the substrings array
let subStr = [];
let n = str.length;
let count = 0;
// Finding each substring of the string
for (let i = 0; i < n; i++) {
for (let j = i + 1; j <= n; j++) {
subStr.push(str.slice(i, j));
}
}
// Checking for the reverse is same or not
subStr.forEach((substring) => {
let subStringReverse = substring
.split('').reverse().join('');
if (subStr.includes(subStringReverse)) {
count++;
}
})
// Displaying results to the users
if (count === subStr.length) {
console.log("Yes");
}
else {
console.log("No");
}
}
isRevPer("xyx");
isRevPer("xyz");
isRevPer("abab");
isRevPer("aba");
Output
Yes No No Yes
Time Complexity: O(n^2), n is the length of the string.
Space Complexity: O(m), m is the length of substring array or number of sub strings.
Efficient Approach
In the efficient approach, we can simply check for the string whether it is a palindrome string or not. If the string is a palindrome, then there will be the reverse of all the substring also avaiable in the string. Otherwise, the reverse of all sub strings will not be present in the string and the string will not be a perfectly reversible string.
Example: The below example will explain the practical implementation of efficient approach to check for the perfect reversible string in JavaScript.
function perRev(str) {
let start = 0;
let end = str.length - 1;
// checking for palindrome string
while (start < end) {
if (str[start] !== str[end]) {
return false;
}
start++;
end--;
}
return true;
}
perRev("xyx") ?
console.log('Yes') : console.log('No');
perRev("xyz") ?
console.log('Yes') : console.log('No');
perRev("abab") ?
console.log('Yes') : console.log('No');
perRev("aba") ?
console.log('Yes') : console.log('No');
Output
Yes No No Yes
Time Complexity: O(n), n is the length of string.
Space Complexity: O(1)
Checking Substrings for Reverse Existence
In this approach, we don't generate all the substrings explicitly. Instead, we iterate through each character in the string and check whether its reverse substring exists in the original string. If all substrings' reverses exist, the string is perfectly reversible.
Example:
function isRevPer(str) {
// Checking for each character whether its reverse exists
for (let i = 0; i < str.length; i++) {
for (let j = i + 1; j <= str.length; j++) {
let substring = str.substring(i, j);
let substringReverse = substring.split('').reverse().join('');
if (!str.includes(substringReverse)) {
return "No";
}
}
}
return "Yes";
}
console.log(isRevPer("xyx"));
console.log(isRevPer("xyz"));
console.log(isRevPer("abab"));
console.log(isRevPer("aba"));
Output
Yes No No Yes
Set-Based Approach
In this approach, we use a Set to store all possible substrings and then check if the reverse of each substring is present in the set. This method combines the efficiency of Set lookups with the straightforwardness of substring generation.
Example:
function isRevPerSet(str) {
let subStrSet = new Set();
let n = str.length;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j <= n; j++) {
subStrSet.add(str.slice(i, j));
}
}
for (let substring of subStrSet) {
let subStringReverse = substring.split('').reverse().join('');
if (!subStrSet.has(subStringReverse)) {
return "No";
}
}
return "Yes";
}
console.log(isRevPerSet("xyx"));
console.log(isRevPerSet("xyz"));
console.log(isRevPerSet("abab"));
console.log(isRevPerSet("aba"));
Output
Yes No No Yes
Frequency-Based Approach
In this approach, we analyze the frequency of each character and their positions in the string. For a string to be perfectly reversible, it should have symmetrical character positions such that any substring’s reverse can be mapped back to a substring in the original string.
Example:
The code example below demonstrates the implementation of the Frequency-Based Approach to check whether a string is perfectly reversible in JavaScript.
function isRevPerFrequency(str) {
let charMap = new Map();
let n = str.length;
for (let i = 0; i < n; i++) {
if (!charMap.has(str[i])) {
charMap.set(str[i], []);
}
charMap.get(str[i]).push(i);
}
for (let [char, positions] of charMap.entries()) {
let len = positions.length;
for (let i = 0; i < Math.floor(len / 2); i++) {
if (positions[i] !== n - 1 - positions[len - 1 - i]) {
return "No";
}
}
}
return "Yes";
}
console.log(isRevPerFrequency("xyx"));
console.log(isRevPerFrequency("xyz"));
console.log(isRevPerFrequency("abab"));
console.log(isRevPerFrequency("aba"));
Output
Yes Yes No Yes