如何比较两个字符串以找到共同的子字符串

时间:2018-10-17 05:27:00

标签: java string

我在编译时由于超时错误而终止。请帮助我

给出两个字符串,确定它们是否共享一个公共子字符串。子字符串可能只有一个字符。

例如,单词“ a”,“ and”,“ art”共享公共子字符串“ a”。 “ be”和“ cat”这两个词不共享子字符串。

输入格式

第一行包含一个整数,即测试用例的数量。

以下几对线如下:

第一行包含字符串s1。 第二行包含字符串s2。

输出格式

对于每对字符串,返回YES或NO。

我在Java中的代码

public static void main(String args[])
{
    String s1,s2;
    int n;
    Scanner s= new Scanner(System.in);
    n=s.nextInt();
    while(n>0)
    {    
    int flag = 0;
        s1=s.next();

    s2=s.next();
    for(int i=0;i<s1.length();i++)
    {
        for(int j=i;j<s2.length();j++)
        {
            if(s1.charAt(i)==s2.charAt(j))
            {
                flag=1;
            }
        }
    }


        if(flag==1)
        {
            System.out.println("YES");
        }
        else
        {
            System.out.println("NO");
        }
        n--;
}
}

}

任何提示?

8 个答案:

答案 0 :(得分:0)

超时的原因可能是:比较每个长度为1.000.000个字符的两个字符串,您的代码始终需要进行1.000.000 * 1.000.000比较。

有一个更快的算法,只需要2 * 1.000.000比较即可。您应该改用更快的算法。其基本思想是:

  • 对于s1中的每个字符:将字符添加到集合中(这是前100万个字符)
  • 对于s2中的每个字符:测试步骤1中的集合是否包含该字符,如果是,则立即返回“是”(这是第二个百万)

Java已经提供了您所需的BitSet数据类型。它的用法如下:

BitSet seenInS1 = new BitSet();
seenInS1.set('x');
seenInS1.get('x');

答案 1 :(得分:0)

由于您担心执行时间,因此如果它们给您期望的字符范围(例如'a''z'),您可以像这样高效地解决它:

import java.util.Arrays;
import java.util.Scanner;

public class Whatever {
    final static char HIGHEST_CHAR = 'z';  // Use Character.MAX_VALUE if unsure.

    public static void main(final String[] args) {
        final Scanner scanner = new Scanner(System.in);
        final boolean[] characterSeen = new boolean[HIGHEST_CHAR + 1];

        mainloop:
        for (int word = Integer.parseInt(scanner.nextLine()); word > 0; word--) {
            Arrays.fill(characterSeen, false);

            final String word1 = scanner.nextLine();
            for (int i = 0; i < word1.length(); i++) {
                characterSeen[word1.charAt(i)] = true;
            }

            final String word2 = scanner.nextLine();
            for (int i = 0; i < word2.length(); i++) {
                if (characterSeen[word2.charAt(i)]) {
                    System.out.println("YES");
                    continue mainloop;
                }
            }

            System.out.println("NO");
        }
    }
}

The code was tested to work with a few inputs

这使用快速数组而不是较慢的集合,并且在整个程序运行过程中仅创建一个非String对象(Scanner除外)。它还以O(n)时间而不是O(n²)时间运行。

唯一可能比数组 快的事物是the BitSet Roland Illig mentioned

如果您想完全落伍,还可以通过以下方式加快速度:

  • 直接将System.in.read(buffer)与可重用的Scanner缓冲区一起使用,从而跳过String和所有这些byte[]对象的创建
  • 通过使自己的非常快的int解析器仅假设它获取有效的非负数{来跳过标准的过程,即花时间检查并正确处理第一行的负数和无效输入。 {1}}后跟换行符

答案 2 :(得分:0)

有多种方法可以解决此问题,但是在线性时间内解决此问题有些棘手。 尽管如此,这个问题仍可以在linear时间内解决。只需以更棘手的方式应用KMP algorithm

假设您有2个字符串。首先找到两个字符串的长度。说string 1的长度大于string 2。将string 1设为text,将string 2设为pattern。如果字符串的长度为n,而模式的长度为m,则上述问题的时间复杂度将为O(m+n),比O(n^2)快得多。

在此问题中,您需要修改KMP algorithm以获得所需的结果。

只需修改KMP

public static void KMPsearch(char[] text,char[] pattern)
    {

        int[] cache = buildPrefix(pattern);

        int i=0,j=0;


        while(i<text.length && j<pattern.length)
        {

            if(text[i]==pattern[j])
                 {System.out.println("Yes");
                return;}
            else{


                if(j>0)
                    j = cache[j-1];
                else
                    i++;

                }

        }


        System.out.println("No");
        return;



    }

Understanding Knuth-Morris-Pratt Algorithm

答案 3 :(得分:0)

public String twoStrings(String sOne, String sTwo) {
    if (sOne.equals(sTwo)) {
        return "YES";
    }

    Set<Character> charSetOne = new HashSet<Character>();
    for (Character c : sOne.toCharArray())
        charSetOne.add(c);

    Set<Character> charSetTwo = new HashSet<Character>();
    for (Character c : sTwo.toCharArray())
        charSetTwo.add(c);

    charSetOne.retainAll(charSetTwo);

    if (charSetOne.size() > 0) {
        return "YES";
    }

    return "NO";
}

这必须工作。经过大量输入测试。

答案 4 :(得分:0)

Python3

def twoStrings(s1, s2):
    flag = False
    for x in s1:
        if x in s2:
            flag = True

    if flag == True: 
        return "YES"
    else:
        return "NO"

if __name__ == '__main__':
    q = 2
    text = [("hello","world"), ("hi","world")]
    for q_itr in range(q):
        s1 = text[q_itr][0]
        s2 = text[q_itr][1]

        result = twoStrings(s1, s2)
        print(result)

答案 5 :(得分:0)

下面是我克服上述相同的HackerRank挑战的方法

static String twoStrings(String s1, String s2) {
    String result="NO";
    Set<Character> set1 = new HashSet<Character>();

   for (char s : s1.toCharArray()){
       set1.add(s);
   }
   
    for(int i=0;i<s2.length();i++){
        if(set1.contains(s2.charAt(i))){
            result = "YES";
            break;
        }
    }
      return result;  
}

它通过了所有测试用例,没有超时问题。

答案 6 :(得分:-1)

解决此问题涉及两个概念。

-理解单个字符是有效的子字符串。
-推断我们只需要知道两个字符串有一个公共子字符串-我们就不需要知道该子字符串是什么。

因此,解决此问题的关键是确定两个字符串是否具有相同的字符。

为此,我们创建了两个集合a和b,其中每个集合都包含出现在以其命名的字符串中的唯一字符。

因为集合26不会存储重复的值,所以我们知道集合的大小永远不会超过英文字母的大小。

此外,这些集合的尺寸很小,因此可以很快找到相交点。

如果两个集合的交集为空,则在新行上打印NO;如果两个集合的交集不为空,则我们知道字符串并共享一个或多个公共字符,并在新行上打印“是”。

在代码中,可能看起来像这样

import java.util.*;

public class Solution {
    static Set<Character> a;
    static Set<Character> b;

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        for(int i = 0; i < n; i++) {
            a = new HashSet<Character>();
            b = new HashSet<Character>();
            for(char c : scan.next().toCharArray()) {
                a.add(c);
            }
            for(char c : scan.next().toCharArray()) {
                b.add(c);
            }

            // store the set intersection in set 'a'
            a.retainAll(b);

            System.out.println( (a.isEmpty()) ? "NO" : "YES" );
        }
        scan.close();
    }
}

答案 7 :(得分:-1)

static String twoStrings(String s1, String s2) {

       for (Character ch : s1.toCharArray()) {
            if (s2.indexOf(ch) > -1)
                return "YES";
        }
        return "NO";
    }