3、Substrings

Problem Description

You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.

 

 

Input

The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string.

 

 

Output

There should be one line per test case containing the length of the largest string found.

 

 

Sample Input

2

3

ABCD

BCDFF

BRCD

2

rose

orchid

 

 

Sample Output

2

2



在这总结一下n个字符串找公共子串的套路:

以最短的子串开始 .    

    1,先截取1个字符,然后到其余的n-1个字符去比较,发现区域的n-1个字符有包含这个字符的,则记录下来,为1个公共字符串,长度为1的子串。如题目中的ABDC,先截取A,然后跟后面2个字符串匹配,发现都没有A,则继续取B比较,发现都有B,则B保存下来。

     2,在第一步的基础上往后再截取1个字符(如果第一步存在1个公共子串,则把第二部截取的字符拼接到第一步的子串后面),然后继续在n-1个字符串中比较,匹配成功了.取C加上第一步的B,构成BC。然后匹配其他2个字符串,发现第三个字符串没有BC,所以BC不可以,放弃,只能取B,公共子串长度仍为1。(注意,BC不可以,不代表C不可以)。

   继续做第一步,发现C可以,再发现D也可以,所以更新为CD。


注意: 

    如果A没有,则以A为前缀的字符串都没有,所以就可以考虑把以A为开头的子串都放弃掉,转向比较B。   



按照这个思路,自己写了一个java版的复杂度为   o(n)

package AA;

public class my 
{
	static String sArray[] = { "ABCD", "BCDFF","CDFFy" };	
	
	
	public static boolean isSubString(String s) {
		boolean flag = true;
		for (String a : sArray) {
			if (a.indexOf(s) == -1 && a.indexOf(inverse(s)) == -1) {
				flag = false;
				break;
			}
		}
		return flag;
	}
	
	
	public static String inverse(String s) {
		String t = "";
		for (char a : s.toCharArray())
			t = a + t;
		return t;
	}
	
	
	
	public static void main(String argc[])
	{
		String f="";
		int i=0,j=1,length=0;
		boolean flag=true;
		String sub="";
		while(true)
		{
			if(i>3)break;
			
			flag=true;
			String t 	= sArray[0];
			String sub1 = t.substring(i,i+j);
			sub = sub+sub1;
			
			
			if( isSubString(sub)==false)
			{
				flag=false;
			}
			
			
			if(flag == true)
			{
				i++;
				f=sub;
			}
			else if(flag ==false)
			{
					sub="";
					i++;
				
			}
	
		}
		
		
		System.out.println(f.length());
	}
		
}

上面的代码从目标串开始检测,我把它称为    “ 头暴力“   ,缺点就是   必须把整个目标串遍历完才能保证找最长子串


下面这段代码我把它称为“尾暴力”,顾名思义,就是从目标串的尾部开始暴力,  优点:可以保证最先找到的公共子串既为最长的公共子串

package AA;
//公共子串问题,暴力破解注意剪枝
public class Test3_2 {
	static String sArray[] = { "rose", "orchid" };

	public static boolean isSubString(String s) {
		boolean flag = true;
		for (String a : sArray) {
			if (a.indexOf(s) == -1 && a.indexOf(inverse(s)) == -1) {
				flag = false;
				break;
			}
		}
		return flag;
	}

	public static String inverse(String s) {
		String t = "";
		for (char a : s.toCharArray())
			t = a + t;
		return t;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int len=sArray[0].length();		
		String t=sArray[0];			 	
		int maxlen=0;					
		for(int k=len;k>=1;k--){		//k不断截取字符串   长度为 4 3 2 1   当4的时候 做1次   当3的时候 做2次  当2的时候做3次  当1的时候,做四次	
										//从长到断,如果碰到了,就不再继续,跟我的那个算法刚好是反过来
		boolean f=true;
		for(int i=0;i<=len-k;i++){		//i?
			int j=i+k;					//j?
			System.out.println(t.substring(i,j));
			if(isSubString(t.substring(i,j))&&j-1+1>maxlen){
				maxlen=k;
				f=false;
				break;//退出内循环达到有效的剪枝效果
			}			
		}
		if(!f)break;//退出外循环达到有效的剪枝效果
		}
		System.out.println(maxlen);
	}

}




动态规划:

以一个m【i】【j】来表示当前   第i个字符到第j个字符的匹配情况,如果第i个字符到第j个字符是匹配的,既第i个字符到第j个字符能在其他串中找到相同的子串,则把m【i】【j】设为true      m【i】【j】为true的条件是   m【i】【j-1】==true   && m【j】【j】==true   &&  第j个字符能匹配


package AA;
//公共子串问题,暴力破解注意剪枝
public class Test3_2 {
	static String sArray[] = { "rose", "orchid" };

	public static boolean isSubString(String s) {
		boolean flag = true;
		for (String a : sArray) {
			if (a.indexOf(s) == -1 && a.indexOf(inverse(s)) == -1) {
				flag = false;
				break;
			}
		}
		return flag;
	}

	public static String inverse(String s) {
		String t = "";
		for (char a : s.toCharArray())
			t = a + t;
		return t;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int len=sArray[0].length();		
		String t=sArray[0];			 	
		int maxlen=0;					
		for(int k=len;k>=1;k--){		//k不断截取字符串   长度为 4 3 2 1   当4的时候 做1次   当3的时候 做2次  当2的时候做3次  当1的时候,做四次	
										//从长到断,如果碰到了,就不再继续,跟我的那个算法刚好是反过来
		boolean f=true;
		for(int i=0;i<=len-k;i++){		//i?
			int j=i+k;					//j?
			System.out.println(t.substring(i,j));
			if(isSubString(t.substring(i,j))&&j-1+1>maxlen){
				maxlen=k;
				f=false;
				break;//退出内循环达到有效的剪枝效果
			}			
		}
		if(!f)break;//退出外循环达到有效的剪枝效果
		}
		System.out.println(maxlen);
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值