Reverse given range of String for M queries
Last Updated :
01 Feb, 2023
Given a string S of length N and an array of queries A[] of size M, the task is to find the final string after performing M operations on the string. In each operation reverse a segment of the string S from position (A[i] to N-A[i]+1).
Examples:
Input: N = 6, S = “abcdef”, M = 3, A = {1, 2, 3}
Output: “fbdcea”
Explanation: After the first operation, the string will be “fedcba”.
After the second operation it will be “fbcdea”.
After the third operation the final string will be “fbdcea”.
Input: N = 2, S = “jc”, M = 5, A = {1, 1, 1, 1, 1}
Output: “cj”
Naive Approach:
A simple solution is to update the string after each operation by reversing it for the given range as defined by the query.
Below is the implementation of the naive approach:
C++
#include <bits/stdc++.h>
using namespace std;
void reverseForAll(string& S, int N, vector< int >& A, int M)
{
for ( int i = 0; i < M; i++) {
int start = A[i] - 1;
int end = N - A[i] + 1;
reverse(S.begin() + start, S.begin() + end);
}
}
int main()
{
int N = 6;
string S = "abcdef" ;
int M = 3;
vector< int > A = { 1, 2, 3 };
reverseForAll(S, N, A, M);
cout << S;
return 0;
}
|
Java
import java.io.*;
class GFG {
public static String reverseForAll(String S, int N,
int A[], int M)
{
String tmp = "" ;
for ( int j = 0 ; j < M; j++) {
int start = A[j] - 1 ;
int end = N - A[j] + 1 ;
tmp = "" ;
for ( int i = 0 ; i < start; i++)
tmp += S.charAt(i);
for ( int i = end - 1 ; i >= start; i--)
tmp += S.charAt(i);
for ( int i = end; i < S.length(); i++)
tmp += S.charAt(i);
S = tmp;
}
return tmp;
}
public static void main(String[] args)
{
int N = 6 ;
String S = "abcdef" ;
int M = 3 ;
int A[] = { 1 , 2 , 3 };
String ans = reverseForAll(S, N, A, M);
System.out.println(ans);
}
}
|
Python3
def reverseForAll( S, N, A, M):
for i in range ( 0 ,M):
start = A[i] - 1 ;
end = N - A[i] + 1 ;
S = S[:start] + "".join( reversed (S[start:end])) + S[end:];
return S;
N = 6 ;
S = "abcdef" ;
M = 3 ;
A = [ 1 , 2 , 3 ];
S = reverseForAll(S, N, A, M);
print (S);
|
C#
using System;
using System.Collections.Generic;
class GFG {
static string reverseForAll( string S, int N, List< int > A, int M)
{
string tmp= "" ;
for ( int j = 0; j < M; j++) {
int start = A[j] - 1;
int end = N - A[j] + 1;
tmp= "" ;
for ( int i=0; i<start; i++)
tmp+=S[i];
for ( int i=end-1; i>=start; i--)
tmp+=S[i];
for ( int i=end; i<S.Length; i++)
tmp+=S[i];
S=tmp;
}
return tmp;
}
public static void Main()
{
int N = 6;
string S = "abcdef" ;
int M = 3;
List< int > A = new List< int >();
A.Add(1);
A.Add(2);
A.Add(3);
string ans=reverseForAll(S, N, A, M);
Console.Write(ans);
}
}
|
Javascript
function reverseForAll(S, N, A, M)
{
for (let i = 0; i < M; i++) {
let start = A[i] - 1;
let end = N - A[i] + 1;
let sub = S.substring(start, end);
sub = sub.split( "" ).reverse().join( "" );
S = S.substring(0, start) + sub + S.substring(end);
}
document.write(S);
}
let N = 6;
let S = "abcdef" ;
let M = 3;
let A = [ 1, 2, 3 ];
reverseForAll(S, N, A, M);
|
Time Complexity: O(M*N)
Auxiliary Space: O(1)
Efficient Approach: Please check out the Difference Array | Range update query in O(1) article before reading this approach.
Observations:
Notice that when the same section of a string is reversed twice it gains back its original state.
As in the example:
For example multiple queries of reversal on the given input
Consider (1-based Indexing) that:
- The first reversal is to be applied to the range [1, 6].
- The second reversal is to be applied to the range [2, 5].
- The third reversal is to be applied to the range [3, 4].
It can be observed that:
- reversal is applied on 1 and 6 indices one time.
- reversal is applied on 2 and 5 indices two times.
- reversal is applied on 3 and 4 indices three times.
In the final string, characters on indices 2 and 5 remained unchanged while indices 1, 3, 4, and 6 are reversed. So, the indices on which reversal is to be applied an even number of times do not take part in the final reversal of string while those with odd no. of reversal queries take part in reversal.
So, the idea of the efficient approach to solve this problem is:
Count for each index, how many queries include this number, if the index is included in even number of queries, it would not be reversed, otherwise if the index is included in odd number of queries it would be reversed.
Follow the steps to solve this problem:
- Take a count array initialized to 0 with a length equal to the length of the string. This will count how many reversal queries include the corresponding index.
- For each query, increment all the values in the range where reversal should be done.
- This increment can be done in O(1) using the concept mentioned in the Difference Array | Range update query in O(1) article.
- Take an empty string and traverse the count array.
- Count array is traversed and for the indices with even value, characters at those indices from the original string are added to the answer string, otherwise, characters from the reversed string are added.
Below is the implementation of the efficient approach:
C++
#include <bits/stdc++.h>
using namespace std;
void updateRange(vector< int >& count, int i, int j)
{
count[i]++;
if (j + 1 < count.size())
count[j + 1]--;
}
void finaliseCountArray(vector< int >& count)
{
for ( int i = 0; i < count.size(); i++)
count[i] += count[i - 1];
}
string reverseForAll(string S, int N, vector< int >& A, int M)
{
vector< int > count(N, 0);
for ( int i = 0; i < M; i++) {
int start = A[i] <= (N + 1) / 2 ? A[i] - 1 : N - A[i];
int end = A[i] <= (N + 1) / 2 ? N - A[i] : A[i] - 1;
updateRange(count, start, end);
}
finaliseCountArray(count);
string temp;
for ( int i = count.size() - 1; i >= 0; i--) {
if (count[i] % 2 != 0)
temp.push_back(S[i]);
}
int i = 0, j = 0;
for (i = 0; i < count.size(); i++) {
if (count[i] % 2 != 0)
S[i] = temp[j++];
}
return S;
}
int main()
{
int N = 6;
string S = "abcdef" ;
int M = 3;
vector< int > A = { 1, 2, 3 };
cout << reverseForAll(S, N, A, M);
return 0;
}
|
Java
import java.io.*;
class GFG {
static void updateRange( int [] count, int i, int j)
{
count[i]++;
if (j + 1 < count.length)
count[j + 1 ]--;
}
static void finaliseCountArray( int [] count)
{
for ( int i = 1 ; i < count.length; i++)
count[i] += count[i - 1 ];
}
static String reverseForAll(String S, int N, int [] A, int M){
int [] count = new int [N];
char str[] = S.toCharArray();
for ( int i = 0 ; i < M; i++) {
int start = A[i] <= (N + 1 ) / 2 ? A[i] - 1 : N - A[i];
int end = A[i] <= (N + 1 ) / 2 ? N - A[i] : A[i] - 1 ;
updateRange(count, start, end);
}
finaliseCountArray(count);
String temp = "" ;
for ( int i = count.length - 1 ; i >= 0 ; i--) {
if (count[i] % 2 != 0 )
temp += S.charAt(i);
}
int j = 0 ;
for ( int i = 0 ; i < count.length; i++) {
if (count[i] % 2 != 0 )
str[i] = temp.charAt(j++);
}
return new String(str);
}
public static void main (String[] args) {
int N = 6 ;
String S = "abcdef" ;
int M = 3 ;
int [] A = { 1 , 2 , 3 };
System.out.println(reverseForAll(S, N, A, M));
}
}
|
Python3
class GFG :
@staticmethod
def updateRange( count, i, j) :
count[i] + = 1
if (j + 1 < len (count)) :
count[j + 1 ] - = 1
@staticmethod
def finaliseCountArray( count) :
i = 1
while (i < len (count)) :
count[i] + = count[i - 1 ]
i + = 1
@staticmethod
def reverseForAll( S, N, A, M) :
count = [ 0 ] * (N)
str = list (S)
i = 0
while (i < M) :
start = A[i] - 1 if A[i] < = int ((N + 1 ) / 2 ) else N - A[i]
end = N - A[i] if A[i] < = int ((N + 1 ) / 2 ) else A[i] - 1
GFG.updateRange(count, start, end)
i + = 1
GFG.finaliseCountArray(count)
temp = ""
i = len (count) - 1
while (i > = 0 ) :
if (count[i] % 2 ! = 0 ) :
temp + = S[i]
i - = 1
j = 0
i = 0
while (i < len (count)) :
if (count[i] % 2 ! = 0 ) :
j = j + 1
str [i] = temp[j - 1 ]
i + = 1
return ''.join( str )
@staticmethod
def main( args) :
N = 6
S = "abcdef"
M = 3
A = [ 1 , 2 , 3 ]
print (GFG.reverseForAll(S, N, A, M))
if __name__ = = "__main__" :
GFG.main([])
|
C#
using System;
public class GFG
{
public static void updateRange( int [] count, int i, int j)
{
count[i]++;
if (j + 1 < count.Length)
{
count[j + 1]--;
}
}
public static void finaliseCountArray( int [] count)
{
for ( int i = 1; i < count.Length; i++)
{
count[i] += count[i - 1];
}
}
public static String reverseForAll(String S, int N, int [] A, int M)
{
int [] count = new int [N];
char [] str = S.ToCharArray();
for ( int i = 0; i < M; i++)
{
var start = A[i] <= ( int )((N + 1) / 2) ? A[i] - 1 : N - A[i];
var end = A[i] <= ( int )((N + 1) / 2) ? N - A[i] : A[i] - 1;
GFG.updateRange(count, start, end);
}
GFG.finaliseCountArray(count);
var temp = "" ;
for ( int i = count.Length - 1; i >= 0; i--)
{
if (count[i] % 2 != 0)
{
temp += S[i];
}
}
var j = 0;
for ( int i = 0; i < count.Length; i++)
{
if (count[i] % 2 != 0)
{
str[i] = temp[j++];
}
}
return new String(str);
}
public static void Main(String[] args)
{
var N = 6;
var S = "abcdef" ;
var M = 3;
int [] A = {1, 2, 3};
Console.WriteLine(GFG.reverseForAll(S, N, A, M));
}
}
|
Javascript
function updateRange(count, i, j) {
count[i] += 1;
if (j + 1 < count.length) {
count[j + 1] -= 1;
}
}
function finalizeCountArray(count) {
for (let i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
}
function reverseForAll(S, N, A, M) {
let count = new Array(N).fill(0);
let str = S.split( '' );
for (let i = 0; i < M; i++) {
let start = A[i] <= Math.ceil((N + 1) / 2) ? A[i] - 1 : N - A[i];
let end = A[i] <= Math.ceil((N + 1) / 2) ? N - A[i] : A[i] - 1;
updateRange(count, start, end);
}
finalizeCountArray(count);
let temp = "" ;
for (let i = count.length - 1; i >= 0; i--) {
if (count[i] % 2 !== 0) {
temp += S[i];
}
}
let j = 0;
for (let i = 0; i < count.length; i++) {
if (count[i] % 2 !== 0) {
j++;
str[i] = temp[j - 1];
}
}
return str.join( '' );
}
let N = 6;
let S = "abcdef" ;
let M = 3;
let A = [1, 2, 3];
document.write(reverseForAll(S, N, A, M));
|
Time Complexity: O(M+N)
Auxiliary Space: O(N)
Share your thoughts in the comments
Please Login to comment...