Solution
General Idea: We need the longest non-decreasing substring we can get after changing at most one character.
Let be the length of the longest sorted substring that ends at position , and let suff[i] be the length of the longest sorted substring that starts at position . Both arrays can be computed in one linear pass each.
If we do not change anything, the answer is the maximum value in .
Now suppose we change the character at position to some letter. There are three useful cases:
Extend the left part: change to s[i-1]. The sorted substring ending at i-1 grows by one character, so we get pre[i-1] + 1.
Extend the right part: change to s[i+1]. The sorted substring starting at i+1 grows by one character on its left, so we get suff[i+1] + 1.
Merge both parts: the sorted substring ending at i-1 and the one starting at i+1 can be joined through position if s[i-1] \le s[i+1]. We then change to any letter between them, for example s[i-1], and the result is pre[i-1] + suff[i+1] + 1.
The answer is the maximum over all positions and all the cases above. For n = 1 the answer is .
The solution runs in time per test case.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
cin >> n;
string s;
cin >> s;
vector<int> pre(n), suff(n);
int cnt = 1, ans = 1;
for (int i = 0; i < n; i++) {
if (i) {
if (s[i] >= s[i - 1]) cnt++;
else cnt = 1;
}
pre[i] = cnt;
ans = max(ans, cnt);
}
cnt = 1;
for (int i = n - 1; i >= 0; i--) {
if (i != n - 1) {
if (s[i] <= s[i + 1]) cnt++;
else cnt = 1;
}
suff[i] = cnt;
ans = max(ans, cnt);
}
for (int i = 0; i < n; i++) {
if (i < n - 1) ans = max(ans, suff[i + 1] + 1);
if (i) ans = max(ans, pre[i - 1] + 1);
if (i > 0 && i < n - 1) {
if (s[i + 1] >= s[i - 1])
ans = max(ans, pre[i - 1] + suff[i + 1] + 1);
}
}
cout << ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
solve();
cout << '\n';
}
return 0;
}