Leetcode 555. Split Concatenated Strings
Problem Explanation
The problem involves receiving a list of strings and having to concatenate these strings together in a loop. You are given the choice to reverse or not reverse each string before concatenating them. The aim is to find the lexicographically biggest string that can be achieved from this process.
To find this biggest string, two main steps need to be around:
- Concatenating all the strings into a loop, where some strings can be reversed and then they are connected in the same order in which they were given.
- Cutting the loop and making one breakpoint in any place, resulting in the looped string becoming a regular one starting from the character at the cutpoint.
The challenge is to find the lexicographically biggest string among all the possible regular strings that can be created through this method.
Walkthrough
Let's explore a simple example to understand this better, with the input being the list of strings: "abc", "xyz". There are several possible loops that can be formed from these strings: "abcxyz", "abczyx", "cbaxyz", "cbazyx". After picking the fourth loop and cutting from the middle character 'a', we get the lexicographically biggest string: "zyxcba".
Approach and Solution
The solution involves iterating through the initial strings and pushing the lexicographically larger between the original string and its reverse to a new list of strings.
Next, we iterate through the new list and for each string and its reversed counterpart, we try all possible breakpoints. We take the substring after our chosen breakpoint, add the remaining part of the loop, and then finally add the substring before our chosen breakpoint. The biggest of all these possibilities gives the answer.
Letโs illustrate with an ASCII art:
Given strings: a-b-c x-y-z
where -
is the breakpoint.
Exploring all possibilities:
1 2ascii 3-abcxyz-, -abczyx-, -cbaxyz-, -cbazyx-
The answer string comes from the fourth looped one, where we could cut from the middle character 'a' and get "zyxcba"
.
Python
1 2python 3class Solution: 4 def splitLoopedString(self, strs: List[str]) -> str: 5 6 strs = [max(s, s[::-1]) for s in strs] 7 res = '' 8 9 for i, s in enumerate(strs): 10 for string in (s, s[::-1]): 11 for j in range(len(string)): 12 res = max(res, string[j:] + ''.join(strs[i+1:] + strs[:i]) + string[:j]) 13 14 return res
Java
1
2java
3public class Solution {
4 public String splitLoopedString(List<String> strs) {
5 List<String> maxStrings = new ArrayList<>();
6
7 for (String str : strs)
8 maxStrings.add(new StringBuilder(str).reverse().toString().compareTo(str) > 0 ? new StringBuilder(str).reverse().toString() : str);
9
10 String res = "";
11
12 for (int i = 0; i < strs.size(); i++) {
13 String str = maxStrings.get(i);
14 String reverse = new StringBuilder(str).reverse().toString();
15
16 for (String fullStr : new String[]{str, reverse}) {
17 for (int cutPos = 0; cutPos < fullStr.length(); cutPos++) {
18 StringBuilder t = new StringBuilder(fullStr.substring(cutPos));
19
20 for (int j = i + 1; j < maxStrings.size(); j++)
21 t.append(maxStrings.get(j));
22
23 for (int j = 0; j < i; j++)
24 t.append(maxStrings.get(j));
25
26 t.append(fullStr.substring(0, cutPos));
27
28 res = t.toString().compareTo(res) > 0 ? t.toString() : res;
29 }
30 }
31 }
32
33 return res;
34 }
35}
JavaScript
1 2javascript 3function splitLoopedString(strs) { 4 let maxStrs = strs.map(s => [...s].reverse().join('') > s ? [...s].reverse().join('') : s); 5 let res = ''; 6 7 for (let i = 0; i < strs.length; i++) { 8 let str = maxStrs[i]; 9 for (let fullStr of [str, [...str].reverse().join('')]) { 10 for (let cutPos = 0; cutPos < fullStr.length; cutPos++) { 11 let t = fullStr.slice(cutPos); 12 for (let j = i + 1; j < maxStrs.length; j++) 13 t += maxStrs[j]; 14 for (let j = 0; j < i; j++) 15 t += maxStrs[j]; 16 t += fullStr.slice(0, cutPos); 17 res = t > res ? t : res; 18 } 19 } 20 } 21 return res; 22}
C++
1
2c++
3class Solution {
4public:
5string splitLoopedString(vector<string>& strs) {
6 for(auto &a:strs)
7 {
8 auto r=a;
9 reverse(begin(r),end(r));
10 a= max(a,r);
11 }
12 string res="";
13 for(int i=0;i<strs.size();i++)
14 {
15 string v=strs[i];
16 string r= v;
17 reverse(r.begin(),r.end());
18 for(auto str:vector<string>({v,r}))
19 {
20 for(int k=0;k<str.size();k++)
21 {
22 string t= str.substr(k)+ accumulate(strs.begin()+i+1,strs.end(),string(""))+
23 accumulate(strs.begin(),strs.begin()+i,string(""))+str.substr(0,k);
24
25 res= max(t,res);
26 }
27
28 }
29
30 }
31 return res;
32
33
34}
35};
C#
1
2csharp
3public class Solution {
4 public string SplitLoopedString(string[] strs) {
5 for (int i = 0; i < strs.Length; i++) {
6 string reverse = new string(strs[i].ToCharArray().Reverse().ToArray());
7 strs[i] = reverse.CompareTo(strs[i]) > 0 ? reverse : strs[i];
8 }
9 string res = "";
10 for (int i = 0; i < strs.Length; i++) {
11 string str = strs[i], reverse = new string(str.ToCharArray().Reverse().ToArray());
12 for (int k = 0; k < str.Length; k++) {
13 strs[i] = str.Substring(k) + String.Join("", strs.Skip(i+1).ToArray()) + String.Join("", strs.Take(i).ToArray()) + str.Substring(0, k);
14 res = strs[i].CompareTo(res) > 0 ? strs[i] : res;
15 strs[i] = reverse.Substring(k) + String.Join("", strs.Skip(i+1).ToArray()) + String.Join("", strs.Take(i).ToArray()) + reverse.Substring(0, k);
16 res = strs[i].CompareTo(res) > 0 ? strs[i] : res;
17 }
18 strs[i] = str;
19 }
20 return res;
21 }
22}
Wrapping Up
The above solution demonstrates how to handle the manipulation of loops, strings and how to get the lexicographically biggest string. Importantly, this kind of problems helps improving problem solving and coding skills.In this problem, the reversal of strings and the selection of breakpoints in the loops play crucial roles. The approach we used for the solution involved creating the maximum versions of the strings we got by reversing them and comparing them with the original strings. We stored these maximum versions of the strings and iterated over them later.
In the next step, we identified each stringโs breakpoints. For each string and its reverse, we checked all possible breaks. We cut the string from a specific breakpoint and stored the substring for future use. To maximize the string lexicographically, we added the rest of the looped strings to it and finally the leftover part from the sliced string. This way, we were able to get the maximum lexicographical strings for all the strings.
The above code snippets in Python, JS, and Java achieve these steps, each has been optimized for minimum memory use and maximum efficiency. In Python, JS, and Java, we have used built-in methods to reverse the strings, slice them from a specific index, and compare strings lexicographically. We have used the map, filter, and reduce functions/methods provided in these languages to perform iterative operations on the list of strings.
This approach is highly efficient and provides the correct solution. However, while writing the code, you should be careful about handling empty strings and null values in the input, which might cause an exception.
By understanding and practicing this problem, you can get a deeper understanding of how strings and loop operations are handled in different programming languages. It can be a good exercise for algorithmic thinking and problem-solving skills. This kind of problem can be a common case in technical interviews, coding tests, or programming contests. Therefore, mastering string and loop operations, lexicographical comparisons, and advanced techniques used in the provided solution can be very beneficial.
Got a question?ย Ask the Teaching Assistantย anything you don't understand.
Still not clear? Ask in the Forum, ย Discordย orย Submitย the part you don't understand to our editors.