给定一个序列,要求求出该序列的最长单调子序列, 即 longest increasing subsequence
这是一个经典的动态规划求解问题。
设给定序列为 a[],大小为 n,如何求其最长单调子序列呢?
考虑将最长单调子序列的长度作为所求的最优值
最长单调子序列必定以序列a[]中的某一个元素结尾,这是废话。
设序列count[i]为以a[i]结尾的最长单调子序列的长度,那么a[]的LIS的长度就是
max{count[i]}, 对所有i
显然此问题具有最优子结构性质,
count[0] = 1, count[i] = max{count[j] | 0 <= j < i, a[j] < a[i]} + 1
据此可得出简单的动态规划算法:
import java.util.Random;
/** sequence resolved with dynamic design
* @author Ewan
* @author http://blog.csdm.net/whmii
*/
public class Sequence {
/** the data of the sequence,
* express as an array
*/
private int[] a;
/**default constructor
* produce an array randomly
*/
public Sequence() {
long seed = System.nanoTime();
Random rand = new Random(seed);
int size = 5 + rand.nextInt(8);
a = new int[size];
for(int i = 0; i < size; i++) {
a[i] = rand.nextInt(50);
}
}
public String toString() {
String result = "";
for(int i = 0, len = a.length; i < len; i++) {
result += a[i];
result += "/t";
}
return result;
}
/** get out the LIS use dynamic design
* time O(n*n)
*/
public int[] LIS() {
int n = a.length;
int currentLISLength; //LIS length end with current element
int maxLength = 0; //the result's length
int endIndex = 0; //the last element's index
int[] count = new int[a.length]; //count[i] stores the LIS ends with a[i]
int[] result;
count[0] = 1; //LIS contains one element at least
for(int i = 1; i < n; i++) {
currentLISLength = 0;
for(int j = 0; j < i; j++) {
if(a[j] <= a[i] && currentLISLength < count[j]) {
//a[j] is in LIS ends with a[i]
currentLISLength = count[j];
}
}
count[i] = currentLISLength + 1; //compute a[i] self
//compute the max length and last element's index of LIS
if(count[i] > maxLength) {
maxLength = count[i];
endIndex = i;
}
}
//store LIS into result[]
result = new int[maxLength];
int index = maxLength;
result[--index] = a[endIndex];
for(int i = endIndex, currentIndex = endIndex; i >=0; i--) {
if(a[i] <= a[currentIndex] && count[i] == count[currentIndex] - 1) {
result[--index] = a[i];
currentIndex = i;
}
}
return result;
}
}