链接:http://lintcode.com/zh-cn/problem/split-concatenated-strings/
给定一个字符串列表,您可以将这些字符串连接到一个循环中,在这个循环中,您可以选择将其反转。在所有可能的循环中,您需要在删除循环之后找到字母顺序最大的字符串,这将使循环字符串成为一个普通的字符串。
具体来说,要找到字母顺序上最大的字符串,您需要经历两个阶段:
1:将所有字符串连接到一个循环中,在这个循环中,您可以反转某些字符串,并按照给定的顺序将它们连接起来。
2:在循环的任意位置切割并制造一个断点,这将使从字符处开始循环的字符串成为一个正常的字符串,你的任务是在所有可能的规则字符串中找到字母顺序上最大的一个。
注意事项
输入字符串只包含小写字母
.
所有字符串的总长度不会超过1000
.
给定 str = ["abc", "xyz"]
, 返回 "zyxcba"
解释:
你可以得到循环字符串“-abcxyz-”,“-abczyx-”,“-cbaxyz-”,“-cbazyx-”,
其中“-”表示循环状态。
答案字符串串从第四个字符串中得来,
你可以从中间的字母a中剪切,得到“zyxcba”。
让我们将其连接起来,连接的时候对于每个字符串我们可以选择翻转或者不翻转,在行程的大的字符串上找一个位置cut掉,将该位置当作首字符,前面的字符串移动到末尾去,问怎么cut能使字符串的字母顺序大。刚开始博主想,既然要让最终字符串字母顺序最大,那么每一个字符串当然要尽可能的大了,所以如果其翻转字符串的字母顺序大的话,就要对字符串进行翻转。然后在组成的字符串中找最大的字符进行cut,然而这种思路不一定能得到正确的结果。比如字符串数组["lc", "love", "ydc"],如果按照博主之前的思路得到的字符串应该为"ydclclove",但正确结果应该是"ylclovecd"。我们可出来正确的答案中cut位置所在的字符串ydc,虽然cdy小于ydc,但还是翻转了。但是其他的字符都是按照字母顺序来确定要不要翻转的,那么我们可以得出这样的结论,只有cut所在的字符串的翻转可能不按规律。那么我们如何确定cut位置呢,其实没有太好的办法,只能遍历每一个字母。我们首先来根据字母顺序确定要不要翻转每一个字符串,将字母顺序大的连成一个字符串,然后遍历每一个字符串,在每一个字符串中遍历每一个位置,将当前遍历的字符串后面的所有字符串跟前面所有字符串先连起来,存入mid中,然后取出当前遍历的字符串中当前遍历的位置及其后面的字符取出,连上mid,然后再连上当前位置前面的字符,然后跟结果res比较,取较大者存入结果res。这里我们可以进行小优化,如果cut位置的字母大于等于结果res的首字母,我们才进行对比更新。注意我们在遍历每个字符串时,要将其翻转字符串的每一位也遍历了,这样才能涵盖所有的情况。
class Solution {
public:
/**
* @param strs: a list of string
* @return: return a string
*/
string splitLoopedString(vector<string>& strs) {
if (strs.empty()) return "";
string s = "", res = "a";
int n = strs.size(), cur = 0;
for (string str : strs) {
string t = string(str.rbegin(), str.rend());
s += str > t ? str : t;
}
for (int i = 0; i < n; ++i) {
string t1 = strs[i], t2 = string(t1.rbegin(), t1.rend());
string mid = s.substr(cur + t1.size()) + s.substr(0, cur);
for (int j = 0; j < strs[i].size(); ++j) {
if (t1[j] >= res[0]) res = max(res, t1.substr(j) + mid + t1.substr(0, j));
if (t2[j] >= res[0]) res = max(res, t2.substr(j) + mid + t2.substr(0, j));
}
cur += strs[i].size();
}
return res;
}
};