我需要在没有交集的情况下连接另一个字符串中的两个字符串(就最后/第一个单词而言)。
例如:
“有些小d”+“小狗很漂亮”=“有些小狗很漂亮”
“我爱你”+“爱”=“我爱你爱”
在Java中执行此操作的最有效方法是什么?
答案 0 :(得分:2)
我们开始 - 如果第一个字母甚至不包含第二个字符串的第一个字母,只需返回连接。否则,在第二个字符串上从最长到最短,看看第一个字符串是否以它结尾。如果是这样,请返回不重叠的部分,否则请缩短一个字母。
public static String docat(String f, String s) {
if (!f.contains(s.substring(0,1)))
return f + s;
int idx = s.length();
try {
while (!f.endsWith(s.substring(0, idx--))) ;
} catch (Exception e) { }
return f + s.substring(idx + 1);
}
docat("Some little d", "little dogs are so pretty");
-> "Some little dogs are so pretty"
docat("Hello World", "World")
-> "Hello World"
docat("Hello", "World")
-> "HelloWorld"
编辑:在回应评论时,这是一个使用数组的方法。我不知道如何正确地对这些进行压力测试,但是我的测试中没有一个花费超过1毫秒。
public static String docat2(String first, String second) {
char[] f = first.toCharArray();
char[] s = second.toCharArray();
if (!first.contains("" + s[0]))
return first + second;
int idx = 0;
try {
while (!matches(f, s, idx)) idx++;
} catch (Exception e) { }
return first.substring(0, idx) + second;
}
private static boolean matches(char[] f, char[] s, int idx) {
for (int i = idx; i <= f.length; i++) {
if (f[i] != s[i - idx])
return false;
}
return true;
}
答案 1 :(得分:1)
最简单:迭代第一个带后缀的字符串(“Some little d”,“ome little d”,“me little d”......)并用.startsWith
测试第二个字符串。找到匹配项时,将第一个字符串的前缀与第二个字符串连接起来。
以下是代码:
String overlappingConcat(String a, String b) {
int i;
int l = a.length();
for (i = 0; i < l; i++) {
if (b.startsWith(a.substring(i))) {
return a.substring(0, i) + b;
}
}
return a + b;
}
这里最大的效率问题是在substring
创建新字符串。实现自定义stringMatchFrom(a, b, aOffset)
应该会改进它,并且是微不足道的。
答案 2 :(得分:1)
您可以使用regionMatches()方法避免创建不必要的子字符串。
public static String intersecting_concatenate(String a, String b) {
// Concatenate two strings, but if there is overlap at the intersection,
// include the intersection/overlap only once.
// find length of maximum possible match
int len_a = a.length();
int len_b = b.length();
int max_match = (len_a > len_b) ? len_b : len_a;
// search down from maximum match size, to get longest possible intersection
for (int size=max_match; size>0; size--) {
if (a.regionMatches(len_a - size, b, 0, size)) {
return a + b.substring(size, len_b);
}
}
// Didn't find any intersection. Fall back to straight concatenation.
return a + b;
}
答案 3 :(得分:0)
以下代码似乎适用于第一个示例。我没有广泛地测试它,但你明白了。它基本上搜索secondString
中firstString
的第一个字符的所有出现,因为这些是可能发生重叠的唯一可能位置。然后它检查第一个字符串的其余部分是否是第二个字符串的开头。当没有找到重叠时,代码可能包含一些错误,......但它更像是我的回答的例证
String firstString = "Some little d";
String secondString = "little dogs are so pretty";
String startChar = secondString.substring( 0, 1 );
int index = Math.max( 0, firstString.length() - secondString.length() );
int length = firstString.length();
int searchedIndex = -1;
while ( searchedIndex == -1 && ( index = firstString.indexOf( startChar, index ) )!= -1 ){
if ( secondString.startsWith( firstString.substring( index, length ) ) ){
searchedIndex = index;
}
}
String result = firstString.substring( 0, searchedIndex ) + secondString;
答案 4 :(得分:0)
isBlank(CharSequence)
,join(T...)
和left(String, int)
是来自Apache Commons的方法。
public static String joinOverlap(String s1, String s2) {
if(isBlank(s1) || isBlank(s2)) { //empty or null input -> normal join
return join(s1, s2);
}
int start = Math.max(0, s1.length() - s2.length());
for(int i = start; i < s1.length(); i++) { //this loop is for start point
for(int j = i; s1.charAt(j) == s2.charAt(j-i); j++) { //iterate until mismatch
if(j == s1.length() - 1) { //was it s1's last char?
return join(left(s1, i), s2);
}
}
}
return join(s1, s2); //no overlapping; do normal join
}
答案 5 :(得分:0)
创建第一个String的suffix tree,然后从根遍历树,从第二个String的开头取字符,并跟踪找到的最长后缀。
这应该是第一个String的最长后缀,它是第二个String的前缀。删除后缀,然后追加第二个String。
这应该可以在线性时间内完成,而不是循环和比较所有后缀所需的二次时间。