1.最长不下降子序列(LIS)
题目描述
设有由n个不相同的整数组成的数列,记为: a(1)、a(2)、……、a(n)且a(i)<>a(j) (i<>j)。例如3,18,7,14,10,12,23,41,16,24。若存在i1<i2<i3<… < ie且有a(i1)<a(i2)<… <a(ie)则称为长度为e的不下降序列。如上例中3,18,23,24就是一个长度为4的不下降序列,同时也有3,7,10,12,16,24长度为6的不下降序列。程序要求,当原数列给出之后,求出最长的不下降序列。
输入
第一行为n,表示n个数(10<=n<=10000)(这个数据范围用普通动态规划法 O(n^2)
第二行n个整数,数值之间用一个空格分隔(1<=a(i)<=n)
输出
最长不下降子序列的长度
样例输入
3
1 2 3
样例输出
3
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
final Scanner scan = new Scanner(System.in);
int n=scan.nextInt();
int []arr=new int[n+1];
for(int i=1;i<=n;i++){
arr[i]=scan.nextInt();
}
int []temp=new int[n+1];
temp[0]=0;
int max=0;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
if(arr[i]>arr[j]){
temp[i]=Math.max(temp[j]+1,temp[i]);
}
}
max=Math.max(max,temp[i]);
}
System.out.println(max);
}
}
2.【提高】最长上升子序列LIS(2)
题目描述
给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。
输入
第一行包含整数N(1≤N≤100000)(数据太大用二分查找法,不然会超时 O(nlogn))
第二行包含N个整数,表示完整序列。
输出
输出一个整数,表示最大长度。
样例输入
6
1 3 2 8 5 6
样例输出
4
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = scan.nextInt();
}
//创建一个tails数组,用于存储最长递增子序列
int[] tails = new int[n];
int len = 0;
for (int i = 0; i < n; i++) {
//获取当前要处理元素
int num = arr[i];
int left = 0;
int right = len - 1;
int insertpos = len;//记录num要插入的位置
//在tails数组里进行二分查找,找第一个比num大的位置,把num替换掉那个位置的值
while (left <= right) {
int mid = left + (right - left) / 2;
if (tails[mid] <num) {
// 如果中间位置的元素小于 num,说明 num 应该插入到 mid 的右侧
left = mid + 1;
} else {
// 如果中间位置的元素大于等于 num,更新插入位置为 mid,并缩小右边界
insertpos = mid;
right = mid - 1;
}
}
tails[insertpos] = num;
// 如果插入位置等于当前最长递增子序列的长度,说明 num 扩展了最长递增子序列
if (insertpos == len) {
len++;
}
}
System.out.println(len);
}
}
import java.util.Scanner;
public class ss {
static int[] arr;
static int n;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = scan.nextInt();
}
// 输出最长严格上升子序列的长度
System.out.println(mid());
// 输出最少的严格上升子序列的划分个数(即最长非严格下降子序列的长度)
System.out.println(midNonIncreasing());
// 输出最长非严格上升子序列的长度
System.out.println(mid2());
// 输出最少的非严格上升子序列的划分个数(即最长严格下降子序列的长度)
System.out.println(midDecreasing());
}
// 计算最长严格上升子序列的长度
public static int mid() {
int[] st = new int[n];
int size = 0;
for (int i = 0; i < n; i++) {
int l = 0, r = size;
while (l < r) {
int mid = l + (r - l) / 2;
if (st[mid] >= arr[i]) {
r = mid;
} else {
l = mid + 1;
}
}
st[l] = arr[i];
if (l == size) {
size++;
}
}
return size;
}
// 计算最长非严格上升子序列的长度
public static int mid2() {
int[] st = new int[n];
int size = 0;
for (int i = 0; i < n; i++) {
int l = 0, r = size;
while (l < r) {
int mid = l + (r - l) / 2;
if (st[mid] > arr[i]) {
r = mid;
} else {
l = mid + 1;
}
}
st[l] = arr[i];
if (l == size) {
size++;
}
}
return size;
}
// 计算最长非严格下降子序列的长度
public static int midNonIncreasing() {
int[] st = new int[n];
int size = 0;
for (int i = 0; i < n; i++) {
int l = 0, r = size;
while (l < r) {
int mid = l + (r - l) / 2;
if (st[mid] < arr[i]) {
r = mid;
} else {
l = mid + 1;
}
}
st[l] = arr[i];
if (l == size) {
size++;
}
}
return size;
}
// 计算最长严格下降子序列的长度
public static int midDecreasing() {
int[] st = new int[n];
int size = 0;
for (int i = 0; i < n; i++) {
int l = 0, r = size;
while (l < r) {
int mid = l + (r - l) / 2;
if (st[mid] <= arr[i]) {
r = mid;
} else {
l = mid + 1;
}
}
st[l] = arr[i];
if (l == size) {
size++;
}
}
return size;
}
}