Reverse given range of String for M queries

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;

  

string reverseForAll(string S, int N,

                     vector<int>& A, int M)

{

    

    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] + 1) : A[i];

  

        

        reverse(S.begin() + start,

                S.begin() + end);

    }

  

    

    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;

}

Output

fbdcea

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;

}

Output

fbdcea

Time Complexity: O(M+N) 
Auxiliary Space: O(N)