LIS 最长递增子序列算法总结

这里包含了三种求得递增子序列的算法。

是以前写的代码,这里就拖过来了。

import java.util.ArrayList;
import java.util.Collections;

public class LIS {
	public static void LIS(int[] L) { // 时间复杂度为O(n^3)

		Long sTime = System.nanoTime();
		int n = L.length;
		int[] A = new int[n];// 用于存放前i个数值中的递增子序列数值个数;
		A[0] = 1;// 以第a1为末元素的最长递增子序列长度为1;
		ArrayList a[] = new ArrayList[L.length];// 存放对应的子序列
		for (int i = 0; i < L.length; i++) {
			a[i] = new ArrayList();
			a[i].add(L[i]);
		}
		for (int i = 1; i < n; i++)// 循环n-1次
		{
			A[i] = 1;
			for (int j = 0; j < i; j++)// 循环i 次
			{
				if (L[j] < L[i] && A[j] > A[i] - 1) {
					A[i] = A[j] + 1;
					while (a[i].size() != 0) {// 最多i次
						a[i].remove(0);
					}
					if (a[j].size() != 0) {
						for (int k = 0; k < a[j].size(); k++)
							// 最多i次
							a[i].add(a[j].get(k));
					}
					a[i].add(L[i]);
				}

			}
		}
		int max = 1, tag = 0; // 找到对应的最长长度和对应的子序列数组链表a[tag]
		for (int i = 0; i < n; i++) {
			if (A[i] > max) {
				max = A[i];
				tag = i;
			}
		}
		System.out.print("LIS最长递增子序列长度为:" + max + "  ");
		System.out.println("LIS最长递增子序列为:");
		// System.out.println(a[tag]);

		Long eTime = System.nanoTime();
		System.out.println("该LIS用时:" + (eTime - sTime) + "纳秒");
	}

	public static void LCSImproveLIS(int[] L) { // 寻找公共子序列法 O(n^2)

		Long sTime = System.nanoTime();
		int n = L.length;
		int[] Temp = new int[n];// 数组B;
		for (int i = 0; i < n; i++)
			Temp[i] = L[i];
		ShellSort(Temp);

		int[][] opt = new int[n + 1][n + 1];
		for (int i = 0; i < n + 1; i++)
			for (int j = 0; j < n + 1; j++)
				opt[i][j] = 0;
		for (int i = n - 1; i >= 0; i--) {
			for (int j = n - 1; j >= 0; j--) {
				if (L[i] == Temp[j])
					opt[i][j] = opt[i + 1][j + 1] + 1;
				else
					opt[i][j] = Math.max(opt[i + 1][j], opt[i][j + 1]);
			}
		}
		System.out.println();
		System.out.print("LCSImproveLIS最长递增子序列长度为:" + opt[0][0] + "  ");
		System.out.println("LCSImproveLIS最长递增子序列为:");
		int i = 0, j = 0;
		while (i < n && j < n) {
			if (L[i] == Temp[j]) {
				// System.out.print(L[i]+",");
				i++;
				j++;
			} else if (opt[i + 1][j] > opt[i][j + 1])
				i++;
			else
				j++;
		}
		System.out.println();
		Long eTime = System.nanoTime();
		System.out.println("该LCSImproveLIS用时:" + (eTime - sTime) + "纳秒");

	}

	public static void ShellSort(int[] x) {

		for (int i = x.length / 2; i > 2; i /= 2) {
			for (int j = 0; j < i; j++)
				insertSort(x, j, i);
		}
		insertSort(x, 0, 1);
	}

	public static void insertSort(int[] x, int start, int incr) {
		int temp;
		for (int i = start + incr; i < x.length; i += incr) {
			for (int j = i; (j >= incr) && (x[j] < x[j - incr]); j -= incr) {
				temp = x[j];
				x[j] = x[j - incr];
				x[j - incr] = temp;
			}
		}
	}

	public static void ImproveLIS(int[] L) { // 性能可以达到O(nlogn)

		Long sTime = System.nanoTime();
		int n = L.length;
		int[] Temp = new int[n + 1];// 数组B;
		Temp[0] = 0; // 取比较最小值0做基准
		Temp[1] = L[0]; // 起始时,起始元素为L[0]

		int ltag, rtag, middle; // 分别为二分查找的上界,下界和中点;
		ArrayList arr = new ArrayList();
		arr.add(Temp[1]);

		int max = 1; // max为最长递增子序列长度 初始化为1;

		int k = 0;

		// 如果arr中的最后一个元素与Temp中最后一个非0元素不一致 则更改arr中的值最多更改N<n个值
		for (int i = 1; i < n; i++) {
			ltag = 0;
			rtag = max;
			while (ltag <= rtag)// 二分查找最末元素小于L[i]的长度最大的最大递增子序列;
			{
				middle = (ltag + rtag) / 2;
				if (Temp[middle] < L[i])
					ltag = middle + 1;
				else
					rtag = middle - 1;
			}

			Temp[ltag] = L[i];// 将长度为p的最大递增子序列的当前最末元素置为ai+1;
			if (ltag == max) {
				k = max - 1;
				// System.out.println((Integer)arr.get(k));
				while ((k >= 0) && ((Integer) arr.get(k) != Temp[k + 1])) {
					arr.set(k, Temp[k + 1]);
					k--;
				}
			}
			if (ltag > max) {
				max++;
				arr.add(Temp[ltag]);
			}

		}
		System.out.print("ImproveLIS最长递增子序列长度为:" + max + "  ");
		System.out.println("ImproveLIS最长递增子序列为:");
		// System.out.println(arr);
		Long eTime = System.nanoTime();
		System.out.println("该ImproveLIS用时:" + (eTime - sTime) + "纳秒");
	}

	public static int[] random(int n) { // 生成n个不同数值的随机数组
		int a[] = new int[n];
		ArrayList arrlist = new ArrayList();
		for (int i = 0; i < a.length; i++)
			arrlist.add(i + 1);

		for (int i = 0; i < a.length; i++) {
			int temp = (int) (Math.random() * arrlist.size());
			int data = (Integer) arrlist.remove(temp);
			a[i] = data;
		}
		return a;
	}

	public static void main(String args[]) {
		int a[], b[], c[], d[];
		d = random(10);
		int n;
		System.out.println("10个随机自然数时");
		for (int i = 0; i < d.length; i++)
			System.out.print(d[i] + "  ");
		System.out.println();

		LIS(d);
		LCSImproveLIS(d);
		ImproveLIS(d);

		System.out.println("1000个随机自然数时");
		a = random(1000);
		LIS(a);
		LCSImproveLIS(a);
		ImproveLIS(a);

		System.out.println("3000个随机自然数时");
		b = random(3000);
		LIS(b);
		LCSImproveLIS(b);
		ImproveLIS(b);

		System.out.println("10000个随机自然数时");
		c = random(10000);
		LIS(c);
		LCSImproveLIS(c);
		ImproveLIS(c);
	}

}
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值