1. 程式人生 > >時間複雜度為O(m*n)最長公共子串

時間複雜度為O(m*n)最長公共子串

什麼叫最長公共子串,就是兩個字串當中最長的連續的公共子串,注意連續;而子序列可以不連續,順序一樣即可,不要混淆。

對於兩個子串,我們先找出短字串L中(長的也可以)每個字元在長字串H中的位置,這樣我們就構建出一個二維表:

L:deasdfe1ra

H:unnasdsdfew333


這樣,我們只需要找到如圖所示類似的向量線就可以了,在構建這樣的二維表時,是按行的循序構建的,每當查詢到x==y時,就給此單元賦值:(x-1,y-1)+1

並同時記錄下最大值MAX和其座標;當表構建完時,只需要拿出最大值得座標,依次右上遍歷,就可以取得最長公共子串了;

這樣演算法的時間複雜度就為O(m*n);//兩子串長度乘積

好吧,我把這件的Java程式碼實現放下面,如果有更好的實現方案,歡迎分享出來,謝謝:

package temp;

import java.util.ArrayList;
import java.util.HashSet;
/**
 * 
 * @author SheyChen
 *
 */
public class Temp {
	/**
	 * 
	 * @param l 短的字串(長的也行)
	 * @param h 長字串
	 * @return 換回最長子串集合,考慮到有多個最大子串長度相等
	 */
	public static HashSet<String> foo(String l, String h) {
		char[] cl = l.toCharArray();
		char[] ch = h.toCharArray();
		int[][] arry = new int[cl.length][ch.length];
		int max = 0;
		/**
		 * List中存放的Int陣列長度為2,第一位子串在是cl中最後一位元素所佔的下標,第二位是子串長度
		 */
		ArrayList<int[]> val = new ArrayList<int[]>();
		/**
		 * 構建二維表
		 */
		for (int i = 0; i < cl.length; i++) {
			for (int j = 0; j < ch.length; j++) {
				if (cl[i] == ch[j]) {
					if (i == 0 || j == 0)
						arry[i][j] = 1;
					else
						arry[i][j] = arry[i - 1][j - 1] + 1;
					if (arry[i][j] == max) {
						int[] temp = { i, max };
						val.add(temp);
					} else if (arry[i][j] > max) {
						max = arry[i][j];
						val.clear();
						int[] temp = { i, max };
						val.add(temp);
					}
				} else {
					arry[i][j] = 0;
				}
			}
		}

		HashSet<String> hs = new HashSet<String>();

		if (val.isEmpty())
			return hs;

		for (int[] in : val) {
			int index = in[0];
			int len = in[1];
			String s = "";
			while (len-- > 0) {
				s = cl[index--] + s;
			}
			hs.add(s);
		}
		return hs;
	}

	public static void main(String[] args) {
		/**
		 * 結果:sdfe
		 */
		String l = "deasdfe1ra";
		String h = "unnasdsdfew333";
		for (String s : foo(l, h)) {
			System.out.println(s);
		}

		System.out.println();
		
		/**
		 * 結果:
		 * 123
		 * dde
		 */
		l = "123kdde123";
		h = "123gddedde";
		for (String s : foo(l, h)) {
			System.out.println(s);
		}
	}
}