寻找两个字符串中的最大相同的子字符串Java

寻找两个字符串中的最大相同的子字符串

    这有点像求最大公约数一样

假设有两个字符串str1,str2,这两个字符串中有且仅存在一个相同的子字符串,如:
        str1 = “abcdhello1efg”;
        str2 = “cvhello1a”;
   可以看得出来,这两个字符串中最大相同的子字符串是“hello1”;
   那么如何通过代码将这个子字符串输出呢?
   我们通过定义两个指针来解决,头指针“head”尾指针“rear”.

  1. 第一大轮是在整个minStr = ‘cvhello1a’的长度中进行判断的,用“cvhello1a”与maxStr进行判断,此时两个指针分别指向’c’和尾’a’。
  2. 第二大轮只减去一个字符然后进行判断,先只减去尾部判断,然后只减去头部进行判断;也就是第一大轮第一次用“cvhello1”进行判断,第一大轮第二次用“vhello1a”进行判断;实质上在第二轮比较开始时,尾指针rear向前移动了一位,指向“cvhello1a”的‘1’,所以开始时是用“cvhello1”进行判断的;判断完之后头尾两个指针同时向右移动一位,分别指向‘v’和‘a’,此时用“vhello1a”再判断。
  3. 第三大轮的时候,先减去尾部的两个字符,指针指向“cvhello”两头,判断完之后两指针同时向后移一位,再用“vhello1”判断,然后再移一位,用“hello1a”判断。
  4. 以此类推,第n大轮就先从尾部减去n个字符,然后指针同时向右移位。直到rear指向minStr的末尾为止。

直接通过代码说明:

//只存在一个相同子字符串
public String getMaxString(String str1,String str2){//传入两个字符串
	if(str1 != null && str2 != null){//判断是否存在最大子字符串的前提是两个字符串都不为空
		//按照长度将两个字符串定义为maxStr和minStr,因为后面循环判断的次数是以短的字符串为标准进行的
		String maxStr = (str1.length() >= str2.length()) ? str1 : str2;
		String minStr = (str1.length() < str2.length()) ? str1 : str2;
		//获取段字符串的长度并作为循环终止条件
		int len = minStr.length();
		for(int i = 0;i < len;i++){//i表示判断的次数,从0开始,相当于每次判断要从minStr字符串中减去的位数
			//此处定义两个指针默认初始时分别指向minStr的首部和位部,相当于指向"cvhello1a"的'c'和'a';
			for(int head = 0,rear = len - i;rear <= len;head++,rear++){//这里可以取'='是因为substring取左不取右的性质
				//将两个指针所指的子字符串赋值给subStr。
				String subStr = minStr.substring(head,rear);
				//如果指针所指的子字符串subStr包含于maxStr,那就说明此时subStr就是最大相同子字符串
				if(maxStr.contains(subStr)){
					return subStr;//返回最大相同子字符串,结束方法,后面不再执行。
				}
			}
		}
	}
	return null;//能走到这一步,说明两个字符串中没有相同子字符串或者至少有一个为空串,返回null。
}

       上述情况是只存在一个相同子字符串,那么也会存在两个字符串中存在两个及以上长度相同的子字符串的情况。这时可以通过另一种方法来实现。
    基本思想和上边是一样的,只是当有多个长度相同的子字符串时候,有一些小点不同,跳出循环的条件有些差别。

//存在一个或多个最大长度相同子字符串
public String[] getSameSizeString(String str1,String str2){
	if(str1 != null && str2 != null){
		String maxStr = (str1.length() >= str2.length()) ? str1 : str2;
		String minStr = (str1.length() < str2.length()) ? str1 : str2;
		int len = minStr.length();
		//后边涉及到将字符串添加到原有的字符串后边,如果用String来存的话,需要不断的新造字符串,影响效率
		//用StringBuilder存放可以提高效率
		StringBuilder builder = new StringBuilder();
		for(int i = 0;i < len;i++){
			for(int head = 0,rear = len - i;rear <= len;head++,rear++){
				String subStr = minStr.sunstring(head,rear);
				if(maxStr.contains(subStr)){
					//如果相同,就将改子字符串加到StringBuilder对象中
					builder.append(subStr + ',');
				}
			}
			//这一步和上边有区别,之前这里是 return subStr;
			//到这一步,已经将内层循环这个长度的字符串遍历完了;如果builder不等于0,说明已经找到了至少了一个相同子字符串,
			//如果让它继续循环,它会去找长度减一的子字符串,长度减二的,减三的...,直到长度为0,输出两个串存在的相同的字符。
			//我们只要找到长度最长的子字符串就可以了,短的就没有意义去寻找了
				if(builder.length() != 0){
				break;
			}
		}
		//将返回的builder通过正则划分,将结尾处的','用 '空' 代替,并且将字符串通过','划分并存入String型数组中
		String[] split = builder.toString().replaceAll(",$","").split("\\,");
		//返回数组
		return split;
	}
	return null;
}
	//最后将调用方法中获取到的返回值,通过Arrays.toString()转成字符串即可

当然,也可以通过ArrayList来解决,上面的方法会比价笨一点。

最后是将两个方法的代码写在一起,测试用例:

/**
 * @author yangyang
 * @create 2020-11-12-9:17 下午
 */

/**
 * 寻找两个字符串中的最大相同的子字符串
 * 前提:只有一个最大相同子字符串
 */
public class StringAlgorithm {
    public String getMaxString(String str1, String str2) {
        if (str1 != null && str2 != null) {
            String maxStr = (str1.length() >= str2.length()) ? str1 : str2;
            String minStr = (str1.length() < str2.length()) ? str1 : str2;
            int len = minStr.length();
            for (int i = 0; i < len; i++) {
                for (int head = 0, rear = len - i; rear <= len; head++, rear++) {
                    String subStr = minStr.substring(head, rear);
                    if (maxStr.contains(subStr)) {
                        return subStr;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 寻找两个字符串中的最大相同的子字符串
     * 有两个或多个相同长度的子字符串
     *
     * @param str1
     * @param str2
     * @return
     */
    public String[] getMaxSameString(String str1, String str2) {
        if (str1 != null && str2 != null) {
            StringBuilder builder = new StringBuilder();
            String maxStr = (str1.length() >= str2.length()) ? str1 : str2;
            String minStr = (str1.length() < str2.length()) ? str1 : str2;
            int len = minStr.length();
            for (int i = 0; i < len; i++) {
                for (int head = 0, rear = len - i; rear <= len; head++, rear++) {
                    String subStr = minStr.substring(head, rear);
                    if (maxStr.contains(subStr)) {
                        builder.append(subStr + ",");
                    }
                }
                if (builder.length() != 0) {
                    break;
                }
            }
            String[] split = builder.toString().replaceAll(",$", "").split("\\,");
            return split;
        }
        return null;
    }

    @Test
    public void getString() {

        String str1 = new String("abcdhello1efg");
        String str2 = new String("cvhello1a");
        StringAlgorithm s = new StringAlgorithm();
        String x = s.getMaxString(str1, str2);
        System.out.println(x);
    }

    @Test
    public void getSameSizeString() {
        String str3 = new String("abcdsfasdfsddhello1efgabcdef");
        String str4 = new String("cvhello1dasdfsdakkabcdef");
        String[] maxSameString = getMaxSameString(str3, str4);
        System.out.println(Arrays.toString(maxSameString));
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值