Reputation: 55
For a while now I have been trying to wrap my head around this seemingly very simple problem. Given a string k, we have to find the optimal way to split that string k into exactly 3 substrings k1, k2, k3 such as that k1 + k2 + k3 = k. A split is optimal if and only if by reversing each substring and joining them back together we get the lexicographically smallest result possible.
For example take a string k = "anakonda". The optimal way to split it is k1 = "a", k2 = "na", k3 = "konda" because after reversing (k1 = "a", k2 = "an", k3 = "adnok") we get k1 + k2 + k3 = "aanadnok" which is the lexicographically smallest possible result.
My first approach was to always end a substring at the next lexicographically smallest character.
std::string str = "anakonda"
int first = find_min(str, 0, str.size() - 3); // Need to have at least 3 substrings so cannot search to the end
std::reverse(str.begin(), str.begin() + first + 1);
...
However this approach is flawed as given the string k = "ggggffffa" the algorithm would not work. I am clueless as to how to correctly solve this problem. So, I am asking for a theoretical solution so that I can try to implement it myself.
Upvotes: 4
Views: 846
Reputation: 143
This algorithm solves the problem but may require optimization:
#include <iostream>
#include <string>
std::string foo(std::string* ss)
{
std::string res;
for (int i = 0; i < 3; i++)
for (int j = ss[i].size()-1; j >= 0; j--)
res.push_back(ss[i][j]);
return res;
}
int main()
{
std::string s = "ggggffffa";
std::string res = "";
for (unsigned int i = 1; i < s.size() - 1; i++)
for (unsigned int j = 0; j < i; j++)
{
std::string ss[3] = {s.substr(0, j+1), s.substr(j+1, i-j), s.substr(i+1)};
std::string r = foo(ss);
if (r < res || res == "") res = r;
}
std::cout << res << std::endl;
}
Description:
for (unsigned int i = 1; i < s.size() - 1; i++)
for (unsigned int j = 0; j < i; j++)
i
, j
and write three substrings in the array of strings;std::string ss[3] = {s.substr(0, j+1), s.substr(j+1, i-j), s.substr(i+1)};
foo
which reverse each substring, concatenate the three parts and returns the resulting string.if (r < res || res == "") res = r;
Upvotes: 1