1. 程式人生 > >動態規劃-最長公共自序列(java)

動態規劃-最長公共自序列(java)

package com.wanali.dynamic_planning;
/**
 * 最長公共自序列LCS(動態規劃求解)
 * @author wan_ys
 *
 * 2019年1月10日上午8:43:34
 */
public class LCS {
	public static void main(String[] args) {
		String[] x = new String[] { "A", "B", "C", "B", "D", "A", "B" };
		String[] y = new String[] { "B", "D", "C", "A", "B", "A" };
		getLCSLength(x, y);

	}
	/**
	 * 計算LCS的長度
	 * @param x 
	 * @param y
	 */
	static void getLCSLength(String[] x, String[] y) {
		int m = x.length + 1;
		int n = y.length + 1;
		int[][] b = new int[m][n];//定義LCS長度陣列
		String[][] c = new String[m][n]; //記錄回溯方向,方便找公共子序列
		//初始化第一列為0
		for (int i = 0; i < m; i++) {
			b[i][0] = 0;
		}
		//初始化第一行為0
		for (int j = 0; j < n; j++) {
			b[0][j] = 0;
		}
		/*從(1,1)開始往後比較x[i]==y[j],b[i][j]=c[i-1][j-1]+1;
		 * b[i-1][j]>=b[i][j-1],則該位置的箭頭向上指
		 * b[i][j-1]>b[i-1][j],則該位置的箭頭向左指
		*/
		for (int i = 1; i < m; i++) {
			for (int j = 1; j < n; j++) {
				//注意這裡應該是x[i-1]和y[j-1]
				if (x[i - 1] == y[j - 1]) {
					b[i][j] = b[i - 1][j - 1] + 1;
					c[i][j] = "upleft";
				} else if (b[i - 1][j] >= b[i][j - 1]) {//上邊位置大於等於左邊位置
					b[i][j] = b[i - 1][j];
					c[i][j] = "up";
				} else {//左邊位置大於上邊位置
					b[i][j] = b[i][j - 1];
					c[i][j] = "left";
				}
			}

		}
		//列印公共子序列的長度
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				System.out.print(b[i][j] + "\t");
			}
			System.out.println();
		}
		//列印回溯方向
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				System.out.print(c[i][j] + "\t");
			}
			System.out.println();
		}
		System.out.println("一個最長公共自序列為:");
		//注意這裡是m-1,n-1
		getLCS(c, x, m-1, n-1);
	}

	static void getLCS(String[][] c, String[] x, int i, int j) {
		if (i == 0 || j == 0) {
			return;
		} 
		if (c[i][j] == "upleft") {
			getLCS(c, x, i - 1, j - 1);
			System.out.print(x[i - 1]);
		} else if (c[i][j] == "up") {
			getLCS(c, x, i - 1, j);
		} else {
			getLCS(c, x, i, j - 1);
		}
	}

}