最长单调递增子序列

前面三篇博客分别讲了贪心,递归,分治,今天就说个简单的动态规划(DP)的题目吧。在我心中DP算是比较难的算法,尤其像状态DP,树形DP,因为实力问题就说一个简单的线性DP——最长单调递增子序列。

题目如下:

计算一个给定整数序列的最长单调递增子序列的长度(最优值)及该序列内容(最优解)。给定一个序列X={x1,x2,…xn},{xi1,xi2,…,xim}称为X的一个长度为m的单调递增子序列,如果满足i1<i2<…<im且 xi1<xi2<…<xim。本问题是找出它的最长单调子序列。例如,序列{3, 8, 10, 4, 12, 5, 6, 8}的最长单调递增子序列是{3, 4, 5, 6, 8}

思路我就不作太多的分析了就一个最简单普通的DP问题,代码里有注释,考虑到osc上好多童鞋对java代码感兴趣所以这次贴的是java代码。下面的代码的时间是O(n*n)不是最优,但是好理解,优化的可以将顺序查找改为二分查找

代码如下:

/*
 * 最长单调递增子序列
 * 1)用一个数组b[n]记录以a[i]结尾的最长单调递增子序列的长度;
 * 2)序列的a的最长单调子序列的长度为max{b[i],0=<i<n};
 * 3)b[i] = max{b[k],a[k]<=a[i]&&0=<k<i} + 1 ,b[0] = 1;
 * 
 * auther:thj
 */
public class LIS
{
	private int[] a;
	private int[] b;

	public LIS(int[] a)
	{
		this.a = a;
		b = new int[a.length];
	}

	public void lis()
	{
		b[0] = 1;

		for (int i = 0; i < a.length; i++)
		{
			int k = 0;
			for (int j = 0; j < i; j++)
			{
				if (a[j] <= a[i] && k < b[j])
				{
					k = b[j];
				}
			}
			b[i] = k + 1;
		}
		int k = max(b);
                //输出结果
		print(k);
	}

	//求数组中最大值下标
	private int max(int[] b)
	{
		int max = b[0];
		int k = 0;
		for (int i = 0; i < b.length; i++)
		{
			if (max < b[i])
			{
				max = b[i];
				k = i;
			}
		}
		return k;
	}

	//输出
	public void print(int k)
	{
		for (int i = k - 1; i >= 0; i--)
		{
			if (b[k] == b[i] + 1 && a[i] <= a[k])
			{
				print(i);
				break;
			}
		}
		System.out.print(a[k] + " ");
	}

	public static void main(String[] args) 
	{
		int[] a = {5, 2, 4, 6, 5, 1, 8};
		LIS lis = new LIS(a);
		lis.lis();
	}
}



你可能感兴趣的:(dp,最长单调递增子序列)