Java-LIS最长递增子序列(动态规划实现)

        问题:找出给定数组最长且单调递增的子序列。

        解决思路:原数组arr的子序列顺序保持不变,而且排序后的array本身是递增的。这样得到的两个序列的子序列一定是递增的序列。要求出数组arr的最长递增子序列,其实就是求数组arr和它的排序数组array的最长公共子序列。

具体过程见代码和注释。

package 字符串;

import java.util.Arrays;
import java.util.Stack;
/**
 * 问题:LIS最长递增子序列。给出一个数组,找出其最长的递增的子序列。
 * 解决思路:原数组arr的子序列顺序保持不变,而且排序后的array本身是递增的。这样得到的两个序列的子序列一定是递增的序列。
 * 		      要求出数组arr的最长递增子序列,其实就是求数组arr和它的排序数组array的最长公共子序列。
 * */
public class Q02_LIS最长递增子序列 {

	public static void main(String[] args) {
		int[] arr = {5,6,7,1,2,3,8};
		int len = arr.length;
		int[] array = new int[len];
		//将arr复制给array
		for(int j = 0; j < arr.length; j++){
			array[j] = arr[j];
		}
		
		//此处可以使用Java中自带的排序方法Arrays.sort(arr);为了练习自写了一个快速排序
		quickSort(array,0,array.length-1);
		
		System.out.print("排序前的数组:");
		for(int i = 0; i < arr.length; i++){
			System.out.print(arr[i] + ",");
		}
		System.out.println();
		System.out.print("排序后的数组:");
		for(int i = 0; i < array.length; i++){
			System.out.print(array[i] + ",");
		}
		System.out.println();
				
		getLCS(arr, array);
	}
	//hinge---枢纽
	public static int findHinge(int[] array, int left, int right){
		int key;
		key = array[left];//记录left,此时array[left]为空
		
		while(left < right){
			while(left < right && array[right] > key){
				right --;
			}
			array[left] = array[right];//此时array[right]为空
			
			while(left < right && array[left] < key){
				left ++;
			}
			array[right] = array[left];//此时array[left]为空
		}
		
		array[left] = key;
		return left;
	}
	//回忆一遍快速排序的算法
	public static void quickSort(int[] array, int left, int right){
		int mid;
		if(left < right){
			mid = findHinge(array, left, right);
			quickSort(array, left, mid -1);
			quickSort(array, mid +1, right);
		}
	}
	
	public static void getLCS(int[] array, int[] data){//两个数组获取最长公共子序列
		int len1 = array.length;
		int len2 = data.length;
		
		int[][] newArr = new int[len1+1][len2+1];
		//设置第0行和第0列为0
		for(int i = 0; i < newArr.length; i++){
			newArr[i][0] = 0;
		}
		for(int j = 0; j < newArr[0].length; j++){
			newArr[0][j] = 0;
		}
		
		//二维数组填写,记录相同的字符序列
		for(int i = 1; i < newArr.length; i++){
			for(int j = 1; j < newArr[i].length; j++){
				if(array[i - 1] == data[j - 1]){
					//动规公式一:LCS(Xm, Yn) = LCS(Xm-1, Yn-1) +Xm
					newArr[i][j] = newArr[i-1][j-1] + 1;
				}else{
					//动规公式二:LCS(Xm, Yn) = MAX{LCS(Xm-1, Yn), LCS(Xm, Yn-1)}
					newArr[i][j] = max(newArr[i-1][j],newArr[i][j-1]);
				}
			}
		}
		
//		//测试数据:将棋盘赋满值,这样可以从右下角开始遍历找出最大公共子序列
//		for(int m = 0; m < newArr.length; m++){
//			for(int n = 0; n < newArr[m].length; n++){
//				System.out.print(newArr[m][n]);
//			}
//			System.out.println();
//		}
		
		Stack<Integer> stack = new Stack();
		int m = array.length - 1;
		int n = data.length - 1;
		while(n >= 0 && m >= 0){//数组从后向前遍历
			if(array[m] == data[n]){//字符相同则入栈
				stack.push(array[m]);
				m--;
				n--;
			}else{
				if(newArr[m+1][n] > newArr[m][n+1]){//字符不同时,根据打印出的二维矩阵(测试数据)查找上一个相同的字符
					n--;
				}else{
					m--;
				}
			}
		}
		
		while(!stack.isEmpty()){//打印出最长的递增子序列
			System.out.print(stack.pop() + ",");
		}
	}
	
	public static int max(int a, int b){
		return (a > b) ? a : b;
	}
	

}
    原文作者:动态规划
    原文地址: https://blog.csdn.net/qq_30507287/article/details/52832362
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞