线性

本文介绍了四个编程问题,涉及线性动态规划解决方案:计算不同爬楼方式的总数、用最少硬币表示特定金额、求最长上升子序列长度以及计算接龙序列长度。通过递推关系展示了如何利用动态规划思想解决这些问题。
摘要由CSDN通过智能技术生成

线性

感觉就是可以凭借一维数组就可以记录每个位置所需的情况,后面的数据会根据前面的推论得知

程序员爬楼

程序员对于每层楼可以爬一层也可以爬三层,问第n层有几种爬楼情况

每一层的爬层要么是上一层直接爬一层,要么是上三层爬三层,所以情况就是 arr[i-1] + arr[i-3]

public static void climbFloor() {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int[] methods = new int[n + 1];
    methods[0] = 1;
    methods[1] = 1;
    methods[2] = 1;
    methods[3] = 2;
    for (int i = 4; i <= n; i++) {
        methods[i] = methods[i - 1] + methods[i - 3];
    }
    System.out.println(methods[n]);
}

硬币情况

就是给定一些已有的硬币,让你求出某个面值最少会被多少硬币表示出来

public static int coinChange(int[] coins, int amount) {
    int[] dp = new int[amount + 1]; // 有初始0,所以数组要多一
    for (int i = 1; i <= amount; i++) {
        dp[i] = -1;
        for (int coin : coins) {
            if (i == coin) { // 如果索引等于对应的面值的话,那么就是本身一张就够了
                dp[i] = 1;
            } else if (i > coin && dp[i - coin] != -1) {
                // 如果索引大于现有的面值,并且对应的去掉此面额的coin已知的找零数量已经确定了
                if (dp[i] == -1) {  // 如果dp[i]还是-1,说明还没有被赋值过,那么就直接赋值
                    dp[i] = dp[i - coin] + 1;  // 此时的dp[coin]是1,因为coin就是本身
                    // 就相当于去掉已有coin的面额的情况加上coin即可
                } else {  // 如果dp[i]不是-1,说明已经被赋值过了,那么就要取最小值
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                }
            }
        }
    }
    return dp[amount];
}

最长上升子序列

给出一行内容,求出最长的上升子序列的长度或值

默认不重复

public static void zuichangshangshengzixulie() {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int[] arr = new int[n];
    for (int i = 0; i < n; i++) {
        arr[i] = sc.nextInt();
    }
    int[] dp = new int[n]; // 存的就是某一位置上所能保持的最长长度
    dp[0] = 1;
    // 初始都设置为0
    int max = 1;
    // 默认最大就是1呗
    for (int i = 1; i < n; i++) {
        // 外层遍历所有的元素
        dp[i] = 1;
        for (int j = 0; j < i; j++) {
            // 内层遍历在这个数之前的所有元素
            // 如果arr[i]大于arr[j],说明arr[i]可以接在arr[j]后面形成一个更长的上升子
            // 序列。这时,dp[i] 被更新为 dp[j] +1 和当前 dp[i] 的较大值。
            if (arr[i] > arr[j]) { // 外层的值大的时候,就说明之前的位置+1,但是要取最大的
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
        max = Math.max(max, dp[i]);
    }
    System.out.println(max);
//        System.out.println(Arrays.toString(dp));
}

public static int maxl(int[] nums, int t){  // 返回大于等于某个数的最小位置的方法。有序
    int n = nums.length;
    int l = 0;
    int r = n - 1;
    int mid = 0;
    while (l <= r){
        mid = l + (r - l) / 2;
        if (nums[mid] < t){
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    return l;
}

// 暂时不理解
public int lengthOfLIS(int[] nums) {
    if (nums == null || nums.length == 0) {
        return 0;
    }
    int[] tails = new int[nums.length];
    int size = 0;
  
    for (int num : nums) {
        int left = 0, right = size;
        while (left != right) {
            int mid = left + (right - left) / 2;
            if (tails[mid] < num) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        tails[left] = num;
        if (left == size) {
            size++;
        }
    }
    return size;

接龙序列

直接拿整体的长度减去最长接龙序列的值即可
public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int[] arr = new int[n];
    for (int i = 0; i < n; i++) {
        arr[i] = sc.nextInt();
    }
    int[] dp = new int[11]; // 这个表示以某个数字结尾的最长子序列的长度
    // 可能以0结尾
    for (int i = 0; i < n; i++) {
        String s = arr[i] + "";
        int head = s.charAt(0) - '0'; // 表示此时的头是什么数
        int tail = s.charAt(s.length() - 1) - '0'; // 表示此时的尾是什么数
        // 以tail结尾的最长子序列的长度,就是以head结尾的最长子序列的长度+1
        // 为啥是呢,是因为自己的头符合别人的尾了,此时自己的头实际上是最长序列的尾,所以要找一个更长的值啊
        // 自己的头符合条件的话,就相当于以自己头结尾的值要+1
        dp[tail] = Math.max(dp[tail], dp[head] + 1);
    }
//        System.out.println(Arrays.toString(dp));
    Arrays.sort(dp);
//        System.out.println(Arrays.toString(dp));
    System.out.println(n - dp[10]);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值