計算兩個字符串的最長公共字串長度(java編程)

最近在做某公司的在線軟件訓練題時,遇到了計算兩個字符串的最長公共字串長度的求解問題,描述如下:


         題目實際完整應敘述爲求兩個字符串的最長連續公共字串長度,例如:ABCDEF 和ABDEF應是3而不是5。

         輸入是以空格爲分隔的兩個字符串,輸出是一個int型整數。

         本文以全字母情況爲例進行說明,程序中判斷時不區分大小寫,算法說明中爲方便匹配全部以大寫爲例。

         算法大致如下:

1,  將輸入以空格爲標誌分割爲s[0]和s[1]兩個字符串。

2,  比較兩個字符串的長度,通過處理,保證短字符串爲s[0],長字符串爲s[1],相等則不用交換,方便下文的比較匹配。

3,  將s[0]和s[1]轉換爲字符數組便於循環處理(下文仍以s[0]和s[1]字符串來敘述)。

4,  以長字符串s[1]爲準,建立兩層循環:第一層負責s[0]頭字符匹配的起始位置移動,從長字符串s[1]的第一個字符到最後一個字符;第二層負責s[0]字符串內的每個字符與s[1]的循環匹配,從短字符串s[0]的第一個字符到最後一個界限字符(當短字符串已經超出長字符串界限時,該界限字符是長字符串的最後一個字符)。如圖:


5,  每一次第二層循環可以得到該次的最長長度,計入一個count數組中,當第一層循環結束時,通過比較獲得count數組中最大的數,即是所求的最長長度了。

 

這裏特別說明一下每一次第二層循環得到該次的最長長度的方法:

考慮到類似下面所示的情況:

                                  

此在第二層循環中我用了一個臨時數組來存儲匹配結果,數組的長度爲短字符串的長度s[0],因爲不可能比s[0]更長了,臨時數組的所有值默認初始化爲0,當從第一個字符開始匹配時,如果匹配成功,則臨時數組內數字下標爲0對應的數字+1,並繼續匹配,如果匹配失敗,則跳到下一個字符,數組中的數字下標也+1,以此類推。因此,MEFDPFRH圖例所得的數組應爲{0,0,0,1,1,1,0,0},而RBCVEFGH圖例所得的數組應該爲{0,2,4,0,0,0,0,0},這次循環完後挑出最大值即結束本次第二層循環。

 

代碼如下:

/**
 * 求兩個字符串的最長連續公共字符串長度
 * @author 田蜜傑果
 * @date   2015/08/17
 */
import java.util.Scanner;

public class Main10 {
	public static void main(String[] args) {
		//1.將輸入以空格爲標誌分割爲s[0]和s[1]兩個字符串
		Scanner sc=new Scanner(System.in);
		String input=sc.nextLine().trim();
		sc.close();
		//判斷輸入是否至少是兩個字符串,當然,如果字符串的數量大於2,只會操作前兩個,後面的字符串拋棄。
		if(input.indexOf(" ")==-1){
			System.exit(0);//如果沒有找到空格,那麼輸入有誤,直接結束
		}
		String[] s=input.split(" ");
		//2,比較兩個字符串的長度,保證短字符串爲s[0],長字符串爲s[1],相等則不用交換
		if(s[0].length()>s[1].length()){
			String temp=s[0];
			s[0]=s[1];
			s[1]=temp;
		}
		//3,將s[0]和s[1]轉換爲字符數組便於循環處理
		char[] s0_char=s[0].toCharArray();
		char[] s1_char=s[1].toCharArray();
		int[] count=new int[s[1].length()];//統計數組,用於保存每次第一層循環匹配的結果,用於最後進行最大長度篩選
		//4,以長字符串s[1]爲準,建立兩層循環
		for(int start=0,end=s[0].length()-1;start<s[1].length();start++){
			int[] temp=new int[s[0].length()];//新建一個臨時數組來存儲匹配結果,數組的長度爲短字符串的長度s[0]
			int tempN=0;//臨時數組內的數字下標
			for(int j=start;j<=end;j++){
				//如果匹配成功,則該數字+1,並繼續匹配
				//匹配的時候,考慮了大小寫,所以if中的條件有3個,這裏使用了截斷或||
				if((s1_char[j]==s0_char[j-start])||(s1_char[j]==s0_char[j-start]+32)||(s1_char[j]==s0_char[j-start]-32)){//忽略大小寫
					temp[tempN]+=1;
				}else{ //如果匹配失敗,臨時數組內的數字下標+1
					tempN++;
				}
				//找出本次循環匹配的臨時數組中最大長度
				int max_temp=temp[0];
				for(int k=1;k<temp.length;k++){   //找出每次匹配最長的個數,這是爲了防止出現匹配時非連續公共串,比如110111這算3個而不是5,101101這算2個而不是4
					if(temp[k]>max_temp){
						max_temp=temp[k];
					}
				}
				count[start]=max_temp;//將該次循環最大長度賦值給統計數組中對應位置的元素
			}
			//判斷結束字符的位置,如果短字符的末尾已經超出長字符串末尾了,那麼比較的結尾字符應該是長字符串的最後一個字符
			if(end>=s[1].length()-1){
				end=s[1].length()-1;
			}else{
				end++;
			}
		}
		//找出統計數組中最大的數字
		int max=count[0];
		for(int k=1;k<count.length;k++){   
			if(count[k]>max){
				max=count[k];
			}
		}
		//輸出結果
		System.out.println(max);
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章