连接两个没有交集的字符串

时间:2012-01-10 17:59:50

标签: java string string-concatenation

我需要在没有交集的情况下连接另一个字符串中的两个字符串(就最后/第一个单词而言)。

例如:

“有些小d”+“小狗很漂亮”=“有些小狗很漂亮”

“我爱你”+“爱”=“我爱你爱”

在Java中执行此操作的最有效方法是什么?

6 个答案:

答案 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)

以下代码似乎适用于第一个示例。我没有广泛地测试它,但你明白了。它基本上搜索secondStringfirstString的第一个字符的所有出现,因为这些是可能发生重叠的唯一可能位置。然后它检查第一个字符串的其余部分是否是第二个字符串的开头。当没有找到重叠时,代码可能包含一些错误,......但它更像是我的回答的例证

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。

这应该可以在线性时间内完成,而不是循环和比较所有后缀所需的二次时间。