43 还原原始字符串
问题描述
给定字符串 S,用一个任意可变整数 K(< S.length)执行若干次以下操作:
S=S+S[k:S.length]
但是我们不知道最开始的 S 是什么。给定最终的字符串 F,输出起始字符串中最短的结果。
假设输入 F:aabbcc
k=3 时,执行第一次操作后,得到的是 S 为:aabbccbcc;
接着让 k=6,在上述 S 基础上,再执行一次 k=6 时的操作,得到新 S 为:aabbccbccbcc
豆包回复
将此问题直接询问豆包,得到结果如下。
要解决这个问题,我们需要找到一个最短的起始字符串 S,使得通过一系列操作可以得到给定的最终字符串 F。我们可以通过以下步骤来解决这个问题:
-
理解问题:
- 给定一个最终字符串
F,我们需要找到一个最短的起始字符串S,使得通过一系列操作可以得到F。 - 操作是:选择一个整数
K,将S和S[k: S.length]拼接起来,得到新的S。
- 给定一个最终字符串
-
关键点:
- 我们需要找到一个最短的
S,使得通过一系列操作可以生成F。 - 这意味着
S应该是F的一个前缀,并且这个前缀可以通过重复自身来生成F。
- 我们需要找到一个最短的
-
数据结构选择:
- 我们可以使用字符串操作来找到最短的前缀。
-
算法步骤:
- 遍历
F的所有可能的前缀。 - 对于每个前缀,检查它是否可以通过重复自身来生成
F。 - 找到最短的前缀,使得它可以生成
F。
- 遍历
通过以上步骤,我们可以找到最短的起始字符串 S,使得通过一系列操作可以得到给定的最终字符串 F。
可以发现,Ai将问题错误理解为S的重复是完全重复,而不是可选择的局部重复。但是暴力的整体思路不变。
思路分析
一开始考虑暴力解法,即依次遍历整个字符串,每次判别字符串是否可以通过重复生成F,如果可以,则此时则为最短的结果。
- 遍历
F的所有可能的前缀。 - 对于每个前缀,检查它是否可以通过重复自身来生成
F。
实现代码
public class Main {
public static String solution(String str1) {
// Edit your code here
if(!str1.equals("")) {
for(int i = 1; i <= str1.length(); i++){
String str = str1.substring(0,i);
if(isMeet(str,str1)){
return str;
}
}
}
return "";
}
public static boolean isMeet(String str, String target) {
if (!target.startsWith(str)) {
return false;
} else {
if (str.length() == target.length()) {
return true;
}
}
for (int i = 0; i < str.length(); i++) {
int count = str.length();
if (str.length() < target.length())
str = str + str.substring(i);
if (isMeet(str, target)) {
return true;
} else {
str = str.substring(0,count);
}
}
return false;
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution("abbabbbabb").equals("ab"));
System.out.println(solution("abbbabbbb").equals("ab"));
System.out.println(solution("jiabanbananananiabanbananananbananananiabanbananananbananananbananananbanananan").equals("jiaban"));
System.out.println(solution("selectecttectelectecttectcttectselectecttectelectecttectcttectectelectecttectcttectectcttectectcttectectcttect").equals("select"));
System.out.println(solution("discussssscussssiscussssscussssdiscussssscussssiscussssscussssiscussssscussss").equals("discus"));
}
}
改进思路
从字符串F出发,可以发现F的末尾字符一定也是原始字符的末尾字符。
例如初始S = "abc",则它不管重复多少次,它的结果字符必定满足末尾字符为c。
根据这一思路,上述代码中的依次遍历字符串则只需查找满足末尾字符等于F的末尾字符的子字符串,然后进行比较。
public class Main {
public static String solution(String str1) {
// Edit your code here
int n = str1.length();
int count = 0;
if(!str1.equals("")) {
char c = str1.charAt(n - 1);
while (true) {
int index = str1.indexOf(c, count++);
String str = str1.substring(0, index + 1);
if (isMeet(str, str1)) {
return str;
}
}
}
return "";
}
public static boolean isMeet(String str, String target) {
if (!target.startsWith(str)) {
return false;
} else {
if (str.length() == target.length()) {
return true;
}
}
for (int i = 0; i < str.length(); i++) {
int count = str.length();
if (str.length() < target.length())
str = str + str.substring(i);
if (isMeet(str, target)) {
return true;
} else {
str = str.substring(0,count);
}
}
return false;
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution("abbabbbabb").equals("ab"));
System.out.println(solution("abbbabbbb").equals("ab"));
System.out.println(solution("jiabanbananananiabanbananananbananananiabanbananananbananananbananananbanananan").equals("jiaban"));
System.out.println(solution("selectecttectelectecttectcttectselectecttectelectecttectcttectectelectecttectcttectectcttectectcttectectcttect").equals("select"));
System.out.println(solution("discussssscussssiscussssscussssdiscussssscussssiscussssscussssiscussssscussss").equals("discus"));
}
}