Given string str of size N containing only lowercase English letters. The task is to encrypt the string such that the substrings having same prefix as itself are replaced by a *. Generate the encrypted string.
Note: If the string can be encrypted in multiple ways, find the smallest encrypted string.
Examples:
Input: str = "ababcababcd"
Output: ab*c*d
Explanation: The substring "ababc" starting from 5th index (0 based indexing) can be replaced by a '*'. So the string becomes "ababcababcd" -> "ababc*d". Now the substring "ab" starting from 2nd index can again be replaced with a '*'. So the string becomes "ab*c*d"Input: str = "zzzzzzz"
Output: z*z*z
Explanation: The string can be encrypted in 2 ways: "z*z*z" and "z**zzz". Out of the two "z*z*z" is smaller in length.
Approach: A simple solution to generate smallest encrypted string is to find the longest non-overlapping repeated substring and encrypt that substring first. To implement this use the following steps:
- Create a stack to store the encrypted string.
- Declare two pointers (i & j) to point to the 1st index and middle index respectively.
- Now start traversing the string and repeat the loop until the entire string is scanned. Follow steps mentioned below for each iteration:
- Compare both the substring from index i and j.
- If both substrings are equal, then repeat the same process on this substring and store the remaining string into stack.
- Else decrement the value of 2nd pointer ( j ) by 1.
- Now pop all the elements from the stack and append a symbol "*" then store it in a output string.
- Return the encrypted string.
Below is the implementation of the above approach.
// C++ code to implement the above approach
#include <bits/stdc++.h>
using namespace std;
// Function to generate the encrypted string
string compress(string str)
{
// Stack to store encrypted string
stack<string> st;
// Variable to store length of string
int N = str.length();
// Variable to point 1st and middle index
int i = 0, j = N / 2;
// Repeat the loop until
// the entire string is checked
while (j > 0) {
int mid = j;
// Compare the substring
// from index 0 to mid-1
// with the rest of the substring
// after mid.
for (i = 0; i < mid && str[i] == str[j]; i++, j++)
;
// If both substrings are equal
// then repeat the same process
// on this substring and store
// the remaining string into stack
if (i == mid) {
st.push(str.substr(j, N - 1));
// Update the value of
// string 'str' with the
// longest repeating substring
str = str.substr(0, i);
// Set the new string length to n
N = mid;
// Initialize the 2nd pointer
// from the mid of new string
j = N / 2;
}
// If both substrings are not equal
// then decrement the 2nd pointer by 1
else {
j = mid - 1;
}
}
// Pop all the elements from the stack
// append a symbol '*' and store
// in a output string
while (!st.empty()) {
str = str + "*" + st.top();
st.pop();
}
return str;
}
// Driver code
int main()
{
// Declare and initialize the string
string str = "zzzzzzz";
cout << compress(str) << "\n";
return 0;
}
// Java code to implement the above approach
import java.util.*;
class GFG{
// Function to generate the encrypted String
static String compress(String str)
{
// Stack to store encrypted String
Stack<String> st = new Stack<String>();
// Variable to store length of String
int N = str.length();
// Variable to point 1st and middle index
int i = 0, j = N / 2;
// Repeat the loop until
// the entire String is checked
while (j > 0) {
int mid = j;
// Compare the subString
// from index 0 to mid-1
// with the rest of the subString
// after mid.
for (i = 0; i < mid && str.charAt(i) == str.charAt(j); i++, j++)
;
// If both subStrings are equal
// then repeat the same process
// on this subString and store
// the remaining String into stack
if (i == mid) {
st.add(str.substring(j, N));
// Update the value of
// String 'str' with the
// longest repeating subString
str = str.substring(0, i);
// Set the new String length to n
N = mid;
// Initialize the 2nd pointer
// from the mid of new String
j = N / 2;
}
// If both subStrings are not equal
// then decrement the 2nd pointer by 1
else {
j = mid - 1;
}
}
// Pop all the elements from the stack
// append a symbol '*' and store
// in a output String
while (!st.isEmpty()) {
str = str + "*" + st.peek();
st.pop();
}
return str;
}
// Driver code
public static void main(String[] args)
{
// Declare and initialize the String
String str = "zzzzzzz";
System.out.print(compress(str)+ "\n");
}
}
// This code is contributed by 29AjayKumar
# Python code for the above approach
# Function to generate the encrypted string
def compress(str):
# Stack to store encrypted string
st = []
# Variable to store length of string
N = len(str)
# Variable to point 1st and middle index
i = 0
j = (int)(N / 2)
# Repeat the loop until
# the entire string is checked
while (j > 0):
mid = j
# Compare the substring
# from index 0 to mid-1
# with the rest of the substring
# after mid.
i=0
while(str[i] == str[j] and i < mid):
i += 1
j += 1
# If both substrings are equal
# then repeat the same process
# on this substring and store
# the remaining string into stack
if (i == mid):
st.append(str[j:N])
# Update the value of
# string 'str' with the
# longest repeating substring
str = str[0:i]
# Set the new string length to n
N = mid
# Initialize the 2nd pointer
# from the mid of new string
j = N // 2
# If both substrings are not equal
# then decrement the 2nd pointer by 1
else:
j = mid - 1
# Pop all the elements from the stack
# append a symbol '*' and store
# in a output string
while (len(st) != 0):
str = str + '*' + st[len(st) - 1]
st.pop()
return str
# Driver code
# Declare and initialize the string
str = "zzzzzzz"
print(compress(str))
# This code is contributed by Saurabh jaiswal
// C# code to implement the above approach
using System;
using System.Collections.Generic;
public class GFG{
// Function to generate the encrypted String
static String compress(String str)
{
// Stack to store encrypted String
Stack<String> st = new Stack<String>();
// Variable to store length of String
int N = str.Length;
// Variable to point 1st and middle index
int i = 0, j = N / 2;
// Repeat the loop until
// the entire String is checked
while (j > 0) {
int mid = j;
// Compare the subString
// from index 0 to mid-1
// with the rest of the subString
// after mid.
for (i = 0; i < mid && str[i] == str[j]; i++, j++)
;
// If both subStrings are equal
// then repeat the same process
// on this subString and store
// the remaining String into stack
if (i == mid) {
st.Push(str.Substring(j, N-j));
// Update the value of
// String 'str' with the
// longest repeating subString
str = str.Substring(0, i);
// Set the new String length to n
N = mid;
// Initialize the 2nd pointer
// from the mid of new String
j = N / 2;
}
// If both subStrings are not equal
// then decrement the 2nd pointer by 1
else {
j = mid - 1;
}
}
// Pop all the elements from the stack
// append a symbol '*' and store
// in a output String
while (st.Count!=0) {
str = str + "*" + st.Peek();
st.Pop();
}
return str;
}
// Driver code
public static void Main(String[] args)
{
// Declare and initialize the String
String str = "zzzzzzz";
Console.Write(compress(str)+ "\n");
}
}
// This code is contributed by shikhasingrajput
<script>
// JavaScript code for the above approach
// Function to generate the encrypted string
function compress(str)
{
// Stack to store encrypted string
let st = [];
// Variable to store length of string
let N = str.length;
// Variable to point 1st and middle index
let i = 0, j = Math.floor(N / 2);
// Repeat the loop until
// the entire string is checked
while (j > 0) {
let mid = j;
// Compare the substring
// from index 0 to mid-1
// with the rest of the substring
// after mid.
for (i = 0; i < mid && str[i] == str[j]; i++, j++)
;
// If both substrings are equal
// then repeat the same process
// on this substring and store
// the remaining string into stack
if (i == mid) {
st.push(str.slice(j, N));
// Update the value of
// string 'str' with the
// longest repeating substring
str = str.slice(0, i);
// Set the new string length to n
N = mid;
// Initialize the 2nd pointer
// from the mid of new string
j = Math.floor(N / 2);
}
// If both substrings are not equal
// then decrement the 2nd pointer by 1
else {
j = mid - 1;
}
}
// Pop all the elements from the stack
// append a symbol '*' and store
// in a output string
while (st.length != 0) {
str = str + '*' + st[st.length - 1];
st.pop();
}
return str;
}
// Driver code
// Declare and initialize the string
let str = "zzzzzzz";
document.write(compress(str) + '<br>');
// This code is contributed by Potta Lokesh
</script>
Output
z*z*z
Time Complexity: O(N. Log(N))
Auxiliary Space: O(N)