提问人:Evgeniy 提问时间:6/1/2022 最后编辑:dani-vtaEvgeniy 更新时间:4/2/2023 访问量:511
Codingbat 挑战:sameEnds
Codingbat challenge: sameEnds
问:
给定任务 sameEnds from CodingBat:
给定一个字符串,返回出现在字符串开头和结尾且不重叠的最长子字符串。例如,sameEnds(“abXab”) 是 “ab”。
sameEnds("abXYab") → "ab"
sameEnds("xx") → "x"
sameEnds("xxx") → "x"
我的解决方案通过了除一项之外的所有测试^:
public String sameEnds(String string) {
String substringFront = "";
String substringEnd = "";
String longestSubstring = "";
for (int i = 1; i < string.length() - 1; i++) {
substringFront = string.substring(0, i);
substringEnd = string.substring(i);
if (substringEnd.contains(substringFront)) {
longestSubstring = substringFront;
}
}
return longestSubstring;
}
这里有什么问题?我该如何解决?
答:
3赞
dani-vta
6/1/2022
#1
代码中存在几个问题:
在到达最后一个字符之前停止迭代,而不是迭代到长度/2 包括(您需要检查开头和结尾而不重叠,因此无需迭代到结尾或几乎)。
你应该从右边开始,所以它应该看起来像.
substringEnd
string.substring(string.length() - i);
下面是一个固定的实现:
public static void main(String[] args) {
List<String> listTest = List.of("abXYab", "xx", "xxx", "xxxx", "javaXYZjava", "javajava", "Hello! and Hello!", "x", "", "abcd", "mymmy");
String substringFront, substringEnd, longestMatch;
for (String string : listTest) {
longestMatch = "";
for (int i = 1; i <= string.length() / 2; i++) {
substringFront = string.substring(0, i);
substringEnd = string.substring(string.length() - i);
if (substringEnd.equals(substringFront) && substringEnd.length() > longestMatch.length()) {
longestMatch = substringEnd;
}
}
if (!listTest.equals("")) {
System.out.printf("%s => %s%n", string, longestMatch);
} else {
System.out.printf("%s => null%n", string);
}
}
}
下面是测试上述代码的链接:
https://www.jdoodle.com/iembed/v0/rEO
但是,为了使其更简洁,您可以使用正则表达式,该正则表达式使用带有贪婪量词的捕获组来匹配字符串的开头,并确保在开始时捕获的内容也与末尾匹配。
^(.+)(.*)\1$
下面是测试正则表达式的链接:
https://regex101.com/r/cgowDQ/1
这可以像这样用 Java 编写:
public static void main(String[] args) {
List<String> listTest = List.of("abXYab", "xx", "xxx", "xxxx", "javaXYZjava", "javajava", "Hello! and Hello!", "x", "", "abcd", "mymmy");
Pattern pattern = Pattern.compile("^(.+)(.*)\\1$");
Matcher matcher;
for (String s : listTest) {
matcher = pattern.matcher(s);
if (matcher.find()) {
System.out.printf("%s => %s%n", s, matcher.group(1));
} else {
System.out.printf("%s => null%n", s);
}
}
}
在这里,您可以测试上面的代码:
https://www.jdoodle.com/iembed/v0/rEK
1赞
Mohammad Rifat Arefin
6/1/2022
#2
迭代到 String 中的最后一个元素,更改循环条件可以解决问题。
for (int i = 1; i < string.length(); i++)
评论
2赞
Harshank Bansal
6/1/2022
您也可以迭代到字符串长度的一半。正如问题所说,它不需要重叠的字符。即i <= string.length()/2
5赞
Andreas Violaris
6/1/2022
#3
除了@Dan和其他人恰当地指出的技术问题外,我还想强调不必要的复杂性问题,这在许多情况下会导致这种逻辑错误。
鉴于此,并考虑到这是一个挑战,我更喜欢一种简约的方法,就像下面的方法一样,它是不言自明的,因此易于理解和调试。
public String sameEnds(String string) {
int middle = string.length() / 2;
for (int i = middle; i >= 0; i--) {
String left = string.substring(0, i);
if (string.endsWith(left)) {
return left;
}
}
return "";
}
0赞
Evgeniy
4/2/2023
#4
该解决方案通过了所有测试:
public String sameEnds(String string) {
String substringFront = "";
String substringEnd = "";
String longestSubstring = "";
for (int i = 1; i < string.length(); i++) {
substringFront = string.substring(0, i);
substringEnd = string.substring(i);
if (substringEnd.contains(substringFront)) {
longestSubstring = substringFront;
}
}
return longestSubstring;
}
评论
i < string.length() - 1
i <= string.length() - 1