代码随想录 刷题记录-18 动态规划(1)基本理论及习题

news2024/9/27 6:44:04

一、基本理论

什么是动态规划

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。

所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的,

动态规划的解题步骤

对于动态规划问题,拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式(状态转移方程)
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

为什么要先确定递推公式,然后在考虑初始化呢?

因为一些情况是递推公式决定了dp数组要如何初始化!

动态规划应该如何debug

找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的。

做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果

然后再写代码,如果代码没通过就打印dp数组,看看是不是和自己预先推导的哪里不一样。

如果打印出来和自己预先模拟推导是一样的,那么就是自己的递归公式、初始化或者遍历顺序有问题了。

如果和自己预先模拟推导的不一样,那么就是代码实现细节有问题。

这样才是一个完整的思考过程。

二、习题

1.509. 斐波那契数

用这道简单题目加深对动态规划五部曲的理解。

动态规划

动规五部曲:

这里我们要用一个一维dp数组来保存递归的结果

1.确定dp数组及下标含义

dp[i]的定义为:第i个数的斐波那契数值是dp[i]

2.确定递推公式

dp[i] = dp[i-1] + dp[i-2]

3.确定dp数组如何初始化

dp[0] = 0;
dp[1] = 1;

4.确定遍历顺序

从递推公式:dp[i] = dp[i-1] + dp[i-2] 可以看出,后面的依赖于前面的,所以要从前往后。

5.举例推到dp数组

按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:

0 1 1 2 3 5 8 13 21 34 55

如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。

代码如下:

class Solution {
    public int fib(int n) {
        if(n==0) return 0;
        int[] dp = new int[n+1];
        dp[0] = 0;
        dp[1] = 1;
        for(int i = 2; i <= n ; i++){
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }
}

也可以滚动维护两个数:

class Solution {
    public int fib(int n) {
        if(n== 0) return 0;
        int[] dp = new int[2];
        dp[0] = 0;
        dp[1] = 1;
        int sum = 0;
        for(int i = 2; i <= n ; i++){
            sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];

    }

}

递归解法

本题还可以使用递归解法来做

代码如下:

class Solution {
public:
    int fib(int N) {
        if (N < 2) return N;
        return fib(N - 1) + fib(N - 2);
    }
};

2.70. 爬楼梯

思路

爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。

那么第一层楼梯再跨两步就到第三层 ,第二层楼梯再跨一步就到第三层。

所以到第三层楼梯的状态可以由第二层楼梯 和 到第一层楼梯状态推导出来,那么就可以想到动态规划了。

爬到第n层楼梯有两种可能:从第n-1层跨一步过来,或者 从第n-2层跨两步过来,那么第n层楼梯的爬法数应当为第n-1层爬法数+第n-2层爬法数。

动规五部曲:

定义一个一维数组来记录不同楼层的状态

1.dp数组及下标含义:

        dp[i]表示爬到第i层可以的方法。

2.确定递推公式:

        根据上面思路中的推导,可以知道 dp[i] = dp[i-1] + dp[i-2]

        在推导dp[i]的时候,一定要时刻想着dp[i]的定义,否则容易跑偏。

3.dp数组初始化:

        dp[1] = 1;

        dp[2] = 2;

        为了统一,dp[0] = 1;(题目中说n!=0,也可以完全不考虑 dp[0]初始化)

4.遍历顺序:

        根据递推公式,后面依赖前面,所以从前往后遍历

5.举例推导dp数组

        当n为5的时候,dp table(dp数组)应该是这样的

代码如下:

class Solution {
    public int climbStairs(int n) {
        if(n==1) return 1;
        if(n==2) return 2;
        int[] dp = new int[n+1];
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 3; i <= n ; i++){
            dp[i] = dp[i-1] + dp[i-2]; 
        }
        return dp[n];
    }
}

优化空间复杂度:

class Solution {
    public int climbStairs(int n) {
        if(n==1) return 1;
        if(n==2) return 2;
        int[] dp = new int[2];
        dp[0] = 1;
        dp[1] = 2;
        int sum = 0;
        for(int i = 3; i <= n ; i++){
            sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];
    }
}

3.746. 使用最小花费爬楼梯

这是一个最优化问题,首先考虑贪心算法,经过简单的 1,100,200举例可知,如果采取贪心策略总选择局部最小的,那么不能达到全局最优。

考虑动态规划。

1.确定dp数组及下标含义

        dp[i]:到达i层,所需要的花费。

2.确定递推公式:

可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[i-2]

dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]。

dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。

那么究竟是选从dp[i - 1]跳还是从dp[i - 2]跳呢?

一定是选最小的

        dp[i] = Math.min(dp[i-1] + cost[i-1] , dp[i-2] + cost[i-2])

3.dp数组初始化

        dp[0] = 0;

        dp[1] = 0;

4.确定遍历顺序:

        根据递推公式,可以知道应当从前往后比遍历

5.举例递推数组

拿示例2:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] ,来模拟一下dp数组的状态变化,如下:

注意本题要到达的时楼梯顶部,而不是最后一个台阶,要返回 dp[cost.length], dp长度应为 cost.length+1;

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int[] dp = new int[cost.length+1];
        dp[0] = 0;
        dp[1] = 0;
        for(int i = 2 ; i <= cost.length ; i++){
            dp[i] = Math.min(dp[i-1] + cost[i-1] , dp[i-2] + cost[i-2]);
        }
        return dp[cost.length];
    }
}

空间优化:

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int dp0 = 0 , dp1 = 0;
        int next = 0;
        for(int i = 2 ; i <= cost.length ; i++){
            next = Math.min(dp0 + cost[i-2], dp1 + cost[i-1]);
            dp0 = dp1;
            dp1 = next;
        }
        return dp1;
    }
}

小结

如果代码写出来了,一直AC不了,灵魂三问:

  1. 这道题目我举例推导状态转移公式了么?
  2. 我打印dp数组的日志了么?
  3. 打印出来了dp数组和我想的一样么?

4.62.不同路径

思路

深搜

这道题目,刚一看最直观的想法就是用图论里的深搜,来枚举出来有多少种路径。

注意题目中说机器人每次只能向下或者向右移动一步,那么其实机器人走过的路径可以抽象为一棵二叉树,而叶子节点就是终点!

如图举例:

此时问题就可以转化为求二叉树叶子节点的个数,代码如下:

class Solution {
private:
    int dfs(int i, int j, int m, int n) {
        if (i > m || j > n) return 0; // 越界了
        if (i == m && j == n) return 1; // 找到一种方法,相当于找到了叶子节点
        return dfs(i + 1, j, m, n) + dfs(i, j + 1, m, n);
    }
public:
    int uniquePaths(int m, int n) {
        return dfs(1, 1, m, n);
    }
};

会超时。

分析一下时间复杂度,这个深搜的算法,其实就是要遍历整个二叉树。

这棵树的深度其实就是m+n-1(深度按从1开始计算)。

那二叉树的节点个数就是 2^(m + n - 1) - 1。可以理解深搜的算法就是遍历了整个满二叉树(其实没有遍历整个满二叉树,只是近似而已)

所以上面深搜代码的时间复杂度为O(2^(m + n - 1) - 1),可以看出,这是指数级别的时间复杂度,是非常大的。

动态规划

机器人从(0 , 0) 位置出发,到(m - 1, n - 1)终点。

按照动规五部曲来分析:

1. dp[i][j] : 从 start 到 i,j有dp[i][j]种路径

2.状态转移方程 ,机器人只能向下或向右移动一步,所以只有可能从上面或者左边过来两种可能:

dp[i][j] = dp[i-1][j] + dp[i][j-1]

3.初始化:

首先dp[i][0]一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0][j]也同理。

所以初始化代码为:

for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;

4.遍历顺序:

根据递推公式,dp[i][j]从左边和上边得来,所以从左到右,从上到下遍历,这样可以保证计算dp[i][j]时一定有所需要的数据。

5.举例推导dp数组

如图所示:

代码如下:

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        for(int i = 0; i < m ; i++) dp[i][0] = 1;
        for(int j = 0; j < n ; j++) dp[0][j] = 1;
        for(int i = 1 ; i < m ; i++){
            for(int j = 1 ; j < n ; j++){
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}
  • 时间复杂度:O(m × n)
  • 空间复杂度:O(m × n)

数论方法

在这个图中,可以看出一共m,n的话,无论怎么走,走到终点都需要 m + n - 2 步。

62.不同路径

在这m + n - 2 步中,一定有 m - 1 步是要向下走的,不用管什么时候向下走。

那么有几种走法呢? 可以转化为,给你m + n - 2个不同的数,随便取m - 1个数,有几种取法。

那么这就是一个组合问题了。

那么答案,如图所示:

62.不同路径2

求组合的时候,要防止两个int相乘溢出! 所以不能把算式的分子都算出来,分母都算出来再做除法。

例如如下代码是不行的。

class Solution {
public:
    int uniquePaths(int m, int n) {
        int numerator = 1, denominator = 1;
        int count = m - 1;
        int t = m + n - 2;
        while (count--) numerator *= (t--); // 计算分子,此时分子就会溢出
        for (int i = 1; i <= m - 1; i++) denominator *= i; // 计算分母
        return numerator / denominator;
    }
};

需要在计算分子的时候,不断除以分母,代码如下:

class Solution {
public:
    int uniquePaths(int m, int n) {
        long long numerator = 1; // 分子
        int denominator = m - 1; // 分母
        int count = m - 1;
        int t = m + n - 2;
        while (count--) {
            numerator *= (t--);
            while (denominator != 0 && numerator % denominator == 0) {
                numerator /= denominator;
                denominator--;
            }
        }
        return numerator;
    }
};
  • 时间复杂度:O(m)
  • 空间复杂度:O(1)

计算组合问题的代码还是有难度的,特别是处理溢出的情况。

5.63. 不同路径 II

62.不同路径中我们已经详细分析了没有障碍的情况,有障碍的话,其实就是标记对应的dp table(dp数组)保持初始值(0)就可以了。

动规五部曲:

1.确定dp数组(dp table)以及下标的含义

dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。

2.确定递推公式

dp[i][j] = dp[i - 1][j] + dp[i][j - 1]

如果有障碍,dp[i][j]保持初始状态0

3.初始化

如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是走不到的位置了,所以障碍之后的dp[i][0]应该还是初始值0。

初始化代码为:

for (int i = 0; i < obstacleGrid.length && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < obstacleGrid[0].length && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;

4.确定遍历顺序

从左到右,从上到下,能保证计算时所需要的数据一定计算过了。

5.举例推导dp数组

拿示例1来举例如题:

63.不同路径II1

对应的dp table 如图:

63.不同路径II2

代码如下:

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];
        for (int i = 0; i < obstacleGrid.length && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
        for (int j = 0; j < obstacleGrid[0].length && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
        for(int i = 1; i < obstacleGrid.length ; i++){
            for(int j = 1; j <obstacleGrid[0].length ; j++){
                if(obstacleGrid[i][j] == 1){
                    dp[i][j] = 0;
                }else{
                    dp[i][j] = dp[i-1][j] +dp[i][j-1];
                }
            }
        }
        return  dp[obstacleGrid.length-1][obstacleGrid[0].length -1];
    }
}

6.343. 整数拆分

思路

动态规划

动规五部曲,分析如下:

1.确定dp数组(dp table)以及下标的含义

dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。

dp[i]的定义将贯彻整个解题过程,下面哪一步想不懂了,就想想dp[i]究竟表示的是啥。

2.确定递推公式

可以想 dp[i]最大乘积是怎么得到的呢?

其实可以从1遍历j,然后有两种渠道得到dp[i].

一个是j * (i - j) 直接相乘。

一个是j * dp[i - j],相当于是拆分(i - j),对这个拆分不理解的话,可以回想dp数组的定义。

那有同学问了,j怎么就不拆分呢?

j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。

如果定义dp[i - j] * dp[j] 也是默认将一个数强制拆成4份以及4份以上了。

所以递推公式:dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});

那么在取最大值的时候,为什么还要比较dp[i]呢?

因为在递推公式推导的过程中,每次计算dp[i],取最大的而已。

3.dp的初始化

dp[0] dp[1]应该初始化多少呢?

有的题解里会给出dp[0] = 1,dp[1] = 1的初始化,但解释比较牵强,主要还是因为这么初始化可以把题目过了。

严格从dp[i]的定义来说,dp[0] dp[1] 就不应该初始化,也就是没有意义的数值。

拆分0和拆分1的最大乘积是多少?

这是无解的。

这里我只初始化dp[2] = 1,从dp[i]的定义来说,拆分数字2,得到的最大乘积是1,这个没有任何异议。

4.确定遍历顺序

确定遍历顺序,先来看看递归公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

dp[i] 是依靠 dp[i - j]的状态,所以遍历i一定是从前向后遍历,先有dp[i - j]再有dp[i]。

所以遍历顺序为:

for (int i = 3; i <= n ; i++) {
    for (int j = 1; j < i - 1; j++) {
        dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
    }
}

注意 枚举j的时候,是从1开始的。从0开始的话,那么让拆分一个数拆个0,求最大乘积就没有意义了。

j的结束条件是 j < i - 1 ,其实 j < i 也是可以的,不过可以节省一步,例如让j = i - 1,的话,其实在 j = 1的时候,这一步就已经拆出来了,重复计算,所以 j < i - 1

至于 i是从3开始,这样dp[i - j]就是dp[2]正好可以通过我们初始化的数值求出来。

更优化一步,可以这样:

for (int i = 3; i <= n ; i++) {
    for (int j = 1; j <= i / 2; j++) {
        dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
    }
}

因为拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的。

例如 6 拆成 3 * 3, 10 拆成 3 * 3 * 4。 100的话 也是拆成m个近似数组的子数 相乘才是最大的。

只不过我们不知道m究竟是多少而已,但可以明确的是m一定大于等于2,既然m大于等于2,也就是 最差也应该是拆成两个相同的 可能是最大值。

那么 j 遍历,只需要遍历到 n/2 就可以,后面就没有必要遍历了,一定不是最大值。

5.举例推导dp数组

举例当n为10 的时候,dp数组里的数值,如下:

343.整数拆分

代码如下:

class Solution {
    public int integerBreak(int n) {
        int[] dp = new int[n+1];
        dp[2] = 1;
        for(int i = 3 ; i <= n ; i++){
            for(int j = 1; j < i ; j++){
                dp[i] = Math.max(dp[i],Math.max( j*(i-j) , j*dp[i-j]));
            }
        }
        return dp[n];
    }
}

贪心

本题也可以用贪心,每次拆成n个3,如果剩下是4,则保留4,然后相乘,但是这个结论需要数学证明其合理性!

我没有证明,而是直接用了结论。感兴趣的同学可以自己再去研究研究数学证明哈。

给出我的C++代码如下:

class Solution {
public:
    int integerBreak(int n) {
        if (n == 2) return 1;
        if (n == 3) return 2;
        if (n == 4) return 4;
        int result = 1;
        while (n > 4) {
            result *= 3;
            n -= 3;
        }
        result *= n;
        return result;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

7.96.不同的二叉搜索树

类似于多少种方案这种问题,考虑到要避免重复计算,后面依赖于前面,可以考虑动态规划思想。

1.dp数组及下标含义

dp[i] : 由i个节点组成且节点值分别为1到i的不同二叉搜索树的个数

2.递推方程

以j为头结点

dp[i] = sum(dp[j-1] * dp[i-j]) 其中 j从1到i

这得益于树的递归定义,比如:

dp[3],就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量

元素1为头结点搜索树的数量 = 右子树有2个元素的搜索树数量 * 左子树有0个元素的搜索树数量

元素2为头结点搜索树的数量 = 右子树有1个元素的搜索树数量 * 左子树有1个元素的搜索树数量

元素3为头结点搜索树的数量 = 右子树有0个元素的搜索树数量 * 左子树有2个元素的搜索树数量

有2个元素的搜索树数量就是dp[2]。

有1个元素的搜索树数量就是dp[1]。

有0个元素的搜索树数量就是dp[0]。

3.初始化

初始化,只需要初始化dp[0]就可以了,推导的基础,都是dp[0]。

那么dp[0]应该是多少呢?

从定义上来讲,空节点也是一棵二叉树,也是一棵二叉搜索树,这是可以说得通的。

从递归公式上来讲,dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量] 中以j为头结点左子树节点数量为0,也需要dp[以j为头结点左子树节点数量] = 1, 否则乘法的结果就都变成0了。

所以初始化dp[0] = 1

4.遍历顺序

从左到右

5.举例推导dp数组

n为5时候的dp数组状态如图:

96.不同的二叉搜索树3

如果自己画图举例的话,基本举例到n为3就可以了,n为4的时候,画图已经比较麻烦了。

这里列到了n为5的情况,是为了方便 debug代码的时候,把dp数组打出来,看看哪里有问题。

代码如下:

class Solution {
    public int numTrees(int n) {
        if(n==1) return 1;
        int[] dp = new int[n+1];
        dp[0] = 1;
        for(int i = 1; i <= n ; i++){
            for(int j = 1; j <= i ; j++){
                dp[i] += dp[j-1]*dp[i-j];
            }
        }
        return dp[n];
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2077297.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

码云 云片滑块 分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我…

小乌龟运动控制-3两只小乌龟

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

【自动驾驶】决策规划算法 | 数学基础(一)五次多项式详解

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

Mysql系列—3.体系架构

目录 Mysql体系结构 Connectors&#xff1a; 连接池和线程管理&#xff1a; SQL Interface&#xff1a; Parser&#xff08;查询解析器&#xff09;&#xff1a; Optimizer&#xff08;优化器&#xff09;&#xff1a; Caches&#xff08;缓存&#xff09;&#xff1a; …

Clickhouse集群化(四)使用clickhouse-operator部署clickhouse集群

clickhouse operator实际下就是帮助我们自动化的生产一些clickhouse配置文件信息&#xff0c;在目录/etc/clickhouse-server/的config.d conf.d users.d 1.1. 部署clickhouse operateor 下载clickhouse-operator.yaml文件 wget https://raw.githubusercontent.com/Altinity/…

Vue3 前端导出Excel表格 Xlsx格式

介绍 xlsx 是一个用于处理 Excel 文件的流行库。可以你读取、生成和操作 Excel 文件&#xff08;.xlsx 格式&#xff09;&#xff0c;提供了强大的功能来处理工作表和单元格数据。可以轻松地将 JSON 数据转换为 Excel 表格&#xff0c;也可以从 Excel 文件中读取数据。 安装 …

【Linux篇】网络请求和下载与端口

目录 1. 网络请求和下载 1.1 ping命令 1.2 wget命令 1.3 curl命令 2. 端口 2.1 查看端口占用 使用nmap命令&#xff0c;安装nmap&#xff1a;yum -y install nmap 可以通过netstat命令&#xff0c;查看指定端口的占用情况。 3. 进程管理 3.1 进程 3.2 查看进程 3.3 …

Llama 4B剪枝蒸馏实战

大型语言模型 (LLM) 因其有效性和多功能性&#xff0c;如今已成为自然语言处理和理解领域的主导力量。LLM&#xff08;例如 Llama 3.1 405B 和 NVIDIA Nemotron-4 340B&#xff09;在许多具有挑战性的任务中表现出色&#xff0c;包括编码、推理和数学。然而&#xff0c;它们的部…

异步编程之std::future(二): std::future和std::promise原理

目录 1.引言 2.源码分析 2.1.std::promise的源码实现 2.2.std::future的源码实现 2.3.关联状态对象的代码实现 3.整个类图 4.future和promise之间的并发安全和线程同步 5.总结 1.引言 异步编程之std::future(一): 使用-CSDN博客 在std::future(一)中详…

【bug】可图文生图模型 KolorsPipeline IndexError: list index out of range

【bug】可图文生图模型 KolorsPipeline IndexError: list index out of range 环境 linux diffusers 0.30.0问题详情 报错详情 from diffusers import KolorsPipelineTraceback (most recent call last):File "Kolors/demo.py", line 6, in <module>pi…

Vue(2)——Vue指令

目录 v-html v-show和v-if v-else和v-else-if v-on v-bind v-for v-model v-html 设置元素的innerHTML <body><div id"app"><div v-html"msg"></div></div><script src"https://cdn.jsdelivr.net/npm/vue2.…

大模型从入门到精通——基于智谱AI和LangChain实现RAG应用(一)

基于智谱AI和LangChain实现RAG应用(一) 1. 使用 LangChain 调用智谱 GLM 1.1 自定义chatglm #!/usr/bin/env python # -*- encoding: utf-8 -*-from typing import Any, List, Mapping, Optional, Dict from langchain_core.callbacks.manager import CallbackManagerForLLM…

统一身份认证服务(CAS)系统实现SSO认识

一、前言 CAS&#xff08;Central Authentication Service&#xff09;即中央认证服务&#xff0c;是 Yale 大学发起的一个企业级开源项目&#xff0c;旨在为 Web 应用系统提供一种可靠的 SSO 解决方案&#xff0c;它是一个企业级的开源单点认证登录解决方案&#xff0c;采用ja…

netty编程之UDP

写在前面 源码 。 UDP&#xff0c;user datagram protocol,是internet协议簇中无连接的传输协议&#xff0c;因为无连接所以相比于TCP需要维护更少的信息以及网络交互&#xff0c;所以具有更高的效率。本文看下netty是如何实现的&#xff0c;和TCP方式差别不大&#xff0c;下面…

【宝马中国-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

Java使用EasyExcel导出图片(原比例大小)到Excel中

EasyExcel导出图片 又开始写Excel导出的需求了&#xff0c;哈哈哈…… 目前的需求是将图表分析对的饼图和折线图&#xff0c;也就是一张完整的图片单独导出到Excel中 为了方便客户在业务报告时&#xff0c;可以使用数据分析图片&#xff0c;从而更清晰准确地展示数据趋势 因…

【C++学习笔记】数据类型与运算符(一)

目录 一、常量与变量 1.1 常量 字面常量 符号常量 1.2 变量 1.3 标识符命名规范 二、数据类型 2.1 整型 2.2 实型&#xff08;浮点型&#xff09; 2.3 字符型 2.4 字符串 2.5 布尔型 三、cin控制台输入 3.1 输入代码 3.2 解决输入中文乱码 四、运算符 4.1 算术…

OpenCV杂项图像变换(1)自适应阈值处理函数adaptiveThreshold()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 函数对数组应用自适应阈值。 该函数根据以下公式将灰度图像转换为二值图像&#xff1a; 对于 THRESH_BINARY: t e x t d s t ( x , y ) { maxV…

# NLP-transformer学习:(5)Bert 实战

NLP-transformer学习&#xff1a;&#xff08;5&#xff09;模型训练和预测 基于 NLP-transformer学习&#xff1a;&#xff08;2,3,4&#xff09;&#xff0c;这里对transformer 更近一步&#xff0c;学习尝试使用其中的bert 文章目录 NLP-transformer学习&#xff1a;&#x…

在 Debian 上安装 IntelliJ IDEA 笔记

在 Debian&#x1f4a9; 上安装 IntelliJ IDEA &#x1f4a1; 笔记 下载安装 JDK17安装 IntelliJ IDEA Community添加创建桌面启动项&#xff08;快捷方式&#xff09; 参考资料 下载 两个包已经下好了&#xff0c;一个JDK17&#xff0c;一个IntelliJ IDEA Community 使用 wge…