最长递增子序列(动态规划法+二分查找法)

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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值