Based on a small suggestion here , this code tries to find lexicographically minimal rotation (question) by successively comparing two adjacent substrings in the very left , that can potentially give us the answer.
Note : Will refer lexicographically smaller char as smaller char and 0-indexing is used
Ex - "abbaad"
Final answer - "aadabb"
My approach is :-
Find out the indices of all the smallest characters. In the above example, [0,3,4]
Start from two leftmost indices :
First smallest index -> pointed by "left" pointer. Here , 0
Second smallest index -> pointed by "right" pointer. Here , 3
Compare corresponding next characters until you find a mismatch. Which is done inside this loop :-
while(i<n/2){
// code
}
The mismatch in our example is when 'b' at 1 is compared to 'a' at 4.
Update the 'left' and 'right' pointers accordingly. Here,
->left is set to right
->right becomes right + 1
This naive algo will give O(n^2) complexity on the test cases like "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" .
The observation is that while we are in the process of comparing corresponding next characters from 'left' and 'right' pointers , if we touch the 'right' pointer (from behind) , then we can remove all the indices of the smallest chars (that we computed in the first step) that lies within the substring of the 'right' pointer that we have traversed so far.
I'll write here but you can also see the first hyperlink.
Ex - "aaaaaaa" : let's say in mid-way , 'left' is 0 and 'right' is 3 . Then for i = 3 , left + i = 3 which is equal to right .
In the first step , our array that stored smallest char indices would be [0,1,2,3,4,5,6] . Then we would remove [3,4,5] from it.
The 'left' pointer stays at 0. But 'right' is now at 6. Hence, we skipped unnecessary computations that would arise with 'right' having values 4 and 5.
But , my solution is giving me tle on the case where string is char 'a' repeated 10^6 times.
I have tried rechecking a lot and also all possible ways of small optimisations like cin.tie(NULL) and using reserve on vector that stored smallest char indices.
#include <bits/stdc++.h>
using namespace std;
#define std_modulo 1000000007
void minimal_rotation()
{
string s;
cin >> s;
if (s.size() == 1)
{
cout << s;
return;
}
// Just some code to extract smallest indices
vector<int> v;
v.reserve(1000000);
for (int i = 0; i < s.size(); i++)
{
if (v.empty())
{
v.push_back(i);
}
else
{
if (s[i] - 'a' <= s[v.back()] - 'a')
{
v.push_back(i);
}
}
}
vector<int> small_indices; // vector of smallest char indices
small_indices.reserve(1000000);
small_indices.push_back(v.back());
for (int i = v.size() - 2; i >= 0; i--)
{
if (s[v[i]] == s[v[i + 1]])
{
small_indices.push_back(v[i]);
}
else
{
break;
}
}
reverse(small_indices.begin(), small_indices.end());
// vector of smallest indices ready
// actual algo begins now
s = s + s;
int n = s.size();
if (small_indices.size() == 1)
{
for (int i = *small_indices.begin(); i < n / 2; i++)
{
cout << s[i];
}
for (int i = 0; i < *small_indices.begin(); i++)
{
cout << s[i];
}
return;
}
// if more than 1 smallest indices
int left = 0;
int right = 1;
while (right < small_indices.size())
{
int i = 0;
while (i < n / 2)
{
// If we touched 'right' pointer from behind
if (small_indices[left] + i == small_indices[right])
{
int removing_range = small_indices[right] + i;
while (right < small_indices.size() && small_indices[right] < removing_range)
{
right++;
}
break;
}
else
{
if (s[small_indices[left] + i] < s[small_indices[right] + i])
{
right++;
break;
}
else if (s[small_indices[left] + i] > s[small_indices[right] + i])
{
left = right;
right = left + 1;
break;
}
else
{
i++;
}
}
}
}
cout << s.substr(small_indices[left], n / 2);
}
int main()
{
minimal_rotation();
}