数据结构——动态规划

news2024/11/27 2:31:05

动态规划有很多重叠子问题,每一个状态一定是由上一个状态推导出来的

贪心没有状态推导,而是从局部直接选最优的

动规五步曲:

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

  • 确定递推公式(容斥原理)

  • dp数组如何初始化

  • 确定遍历顺序

  • 举例推导dp数组(用于检验)

一:递推问题

1.1. 如何求解递推问题

正向递推:(递推:一个算法     递归:程序实现的方式,不是算法) 

正向递推(慢):n-------》1-------》递归

逆向递推(快):1-------》n-------》循环  

解决效率过差:

1. 递归过程+记忆化

2. 改成逆向递推求解

动规五步曲:

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

        dp[n]:第n个月的兔子总数是dp[n]

  • 确定递推公式(容斥原理)

        容斥原理 :dp[n]全集包括:成年兔 + 幼年兔

        dp[n] = dp[n - 1] + dp[n - 2];

  • dp数组如何初始化

        dp[1] = 1;

        dp[2] = 2;

  • 确定遍历顺序

        从前往后

  • 举例推导dp数组(用于检验)

代码实现:

#include <stdio.h>
#include <stdlib.h>
//正向递推:递归过程+记忆化(提高运行效率)
#define MAX_N 100
int arr[MAX_N + 1] = {0};
int func1(int n) {
    if (n <= 2) {
        return n;
    }
    if (arr[n]) {
        return arr[n];
    }
    arr[n] = func1(n - 1) + func1(n - 2);
    return arr[n];
}

//逆向递推
int func2(int n) {
    int *dp = malloc(sizeof(int) * (n + 1));
    dp[1] = 1;
    dp[2] = 2;
    for (int i = 3; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    int ret = dp[n];
    free(dp);
    return ret;
} 

int main(int argc, char *argv[]) {
    int n;
    scanf("%d", &n);
    printf("%d\n", func1(n));
    printf("%d\n", func2(n));
    return 0;
}

1.2. 容斥原理的基本思想

动规五步曲:

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

        dp[i][j]:用前 i 种钱币,凑足 j 元钱的方法总数

  • 确定递推公式(容斥原理)

        容斥原理:dp[i][j]全集包括:没有使用第i种钱币 + 使用第i种钱币

        没有使用第i种钱币:dp[i - 1][j]

        使用第i种钱币:dp[i][j - value[i]]

                                  第一部分:给第i种钱币先留出一个空,用前i种钱币凑够(j - value[i])钱 

                                  第二部分:最后一个空用第i种钱币

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

  • dp数组如何初始化

1)

        

        

//初始化
for (int i = 1; i <= m; i++) {
    dp[i][0] = 1;
}
for (int j = 1; j <= n; j++) {
    if (w[1] <= j && (j % w[1] == 0)) {
        dp[1][j] = 1;
    } else {
        dp[1][j] = 0;
    }
}

2)

//初始化
memset(dp[0], 0, sizeof(int) * n); //将第0行初始化为0
for (int i = 1; i <= m; i++) {
    dp[i][0] = 1; //初始化第i行第0列为1
}
  • 确定遍历顺序

        从前往后

  • 举例推导dp数组(用于检验)

代码实现:

//1)动态规划
#include <stdio.h>
#define MAX_N 10000
#define MAX_M 20
int w[MAX_M + 1];
int dp[MAX_M + 1][MAX_N + 1];

int main(int argc, char *argv[]) {
    int m, n; //m种面额的钱币凑足n元钱
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= m; i++) {
        scanf("%d", w + i);
    }
    //初始化
    for (int i = 1; i <= m; i++) {
        dp[i][0] = 1;
    }
    for (int j = 1; j <= n; j++) {
        if (w[1] <= j && (j % w[1] == 0)) {
            dp[1][j] = 1;
        } else {
            dp[1][j] = 0;
        }
    }

    for (int i = 2; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            dp[i][j] = dp[i - 1][j];
            if (j < w[i]) {
                continue;
            }
            dp[i][j] += dp[i][j - w[i]];
            dp[i][j] %= 9973;
        }
    }
    printf("%d\n", dp[m][n]);
    return 0;
}

//2)动态规划
#include <stdio.h>
#include <string.h>

#define MAX_N 10000
#define MAX_M 20
int w[MAX_M + 5];
int dp[MAX_M + 5][MAX_N + 5];

int main(int argc, char *argv[]) {
    int m, n; //m种面额的钱币凑足n元钱
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= m; i++) {
        scanf("%d", w + i);
    }
    memset(dp[0], 0, sizeof(int) * n); //将第0行初始化为0
    for (int i = 1; i <= m; i++) {
        dp[i][0] = 1; //初始化第i行第0列为1
        for (int j = 1; j <= n; j++) {
            dp[i][j] = dp[i - 1][j];
            if (j < w[i]) {
                continue;
            }
            dp[i][j] += dp[i][j - w[i]];
            dp[i][j] %= 9973;
        }
    }
    printf("%d\n", dp[m][n]);
    return 0;
}

//3)回溯

1.3. 随堂练习1:爬楼梯

动规五步曲:

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

        dp[n]:走到第n阶台阶的方法总数

  • 确定递推公式(容斥原理)

        容斥原理:dp[n]全集包括:最后跨2步到达第n阶台阶 + 最后跨3步到达第n阶台阶

        dp[n] = dp[n - 2] + dp[n - 3];

  • dp数组如何初始化

        dp[1] = 0;

        dp[2] = 1;

  • 确定遍历顺序

        从前往后

  • 举例推导dp数组(用于检验)

代码实现:

#include <stdio.h>

#define MAX_N 500
int dp[MAX_N + 1];

int func(int n) {
    dp[0] = 1;
    dp[1] = 0;
    dp[2] = 1;
    for (int i = 3; i <= n; i++) {
        dp[i] = dp[i - 2] + dp[i - 3];
    }
    return dp[n];
}

int main(int argc, char *argv[]) {
    int n;
    scanf("%d", &n);
    printf("%d\n", func(n));
    return 0;
}

💖1.4. 随堂练习1:墙壁涂色

   

动规五步曲:

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

       dp[n][i][j]代表前n块墙壁,在不考虑头尾成环的前提下,第1块涂颜色i,第n块涂颜色j的方法总数

        此时 i 可以等于 j ,最后统计答案时去除相等的情况

  • 确定递推公式(容斥原理)

        容斥原理:dp[n][i][j]全集包括:第1块涂颜色i,第n-1块涂颜色k(k != j),第n块涂颜色j

        dp[n][i][j] = dp[n-1][i][k](k != j)的累加

  • dp数组如何初始化

        

        

  • 确定遍历顺序

        从前往后

  • 举例推导dp数组(用于检验)

     

二:递推-课后实战题

2.1. 数的划分

动规五步曲:

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

        dp[i][j]:将数字 i 分成 j 份的方法总数

  • 确定递推公式(容斥原理)

        容斥原理:dp[i][j]全集包括:拆分方案中有1 + 拆分方案中没有1

        拆分方案中有1:留下最后一个位置放1,dp[i - 1][j - 1]

        拆分方案中没有1:将所有方案中的 j 个数都减1,得到另外一个数(i - j)分成 j                                        份的结果,将i - j的所有方案列出来,每个数都加上1,就是拆分方                                         案中没有1的结果,所以拆分方案中没有1的方法总数 == 将数字 i  -                                         j分成 j 份的方法总数 ,即dp[i - j][j]

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

  • dp数组如何初始化

        

        

int dp[MAX_N + 1][MAX_K + 1] = {0};
for (int i = 1; i <= n; i++) {
        dp[i][1] = 1;
}
  • 确定遍历顺序

        从前往后

  • 举例推导dp数组(用于检验)

代码实现:

//动态规划
#include <stdio.h>

#define MAX_N 200
#define MAX_K 6
#define min(a, b) ((a) > (b) ? (b) : (a))

int dp[MAX_N + 1][MAX_K + 1] = {0};

int main(int argc, char *argv[]) {
    int n, k;
    scanf("%d%d", &n, &k);
    dp[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        dp[i][1] = 1;
        for (int j = 2; j <= min(i, k); j++) {
            dp[i][j] = dp[i - 1][j - 1] + dp[i - j][j];
        }
    }
    printf("%d\n", dp[n][k]);
    return 0;
}

//回溯

2.2. 数的计算

动规五步曲:

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

       dp[i]:以i作为开头的合法的数列个数

  • 确定递推公式(容斥原理)

        容斥原理:dp[i]全集包括:

                          以i作为结尾(不扩展)+ i后面接i/2 + i后面接i/2-1 ...... + i后面接1

                                    1                             dp[i/2]          dp[i/2-1]                dp[1]

        dp[i] = dp[j]的累加(j <= i/2)+ 1                                     

  • dp数组如何初始化

        

  • 确定遍历顺序

        从前往后

  • 举例推导dp数组(用于检验)

代码实现:

#include <stdio.h>

#define MAX_N 1000
int dp[MAX_N + 1] = {0};

int main(int argc, char *argv[]) {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        dp[i] = 1;
        for (int j = 1; j <= i / 2; j++) {
            dp[i] += dp[j];
        }
    }
    printf("%d\n", dp[n]);
    return 0;
}

2.3. 神经网络

2.4. 栈

题目描述:1 <= n <=18 的合法出栈序列一共有多少种

动规五步曲:

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

        dp[n]:1—n的合法出栈序列方案数

  • 确定递推公式(容斥原理)

        容斥原理:dp[n]全集包括:出栈序列末尾是1的方案数 + 出栈序列末尾是2的方案数 + 出栈序列末尾是3的方案数 + ...... + 出栈序列末尾是n的方案数

        小于x的数不断入栈出栈---》x入栈---》大于x的数不断入栈出栈---》x出栈

        第一部分:小于x的数   第二部分:大于x的数   第三部分:x

        所以出栈序列末尾是x的方案数 = dp[x - 1] * dp[n - x]

        dp[n] = dp[x - 1] * dp[n - x]的累加(x == 1; x <= n; x++)

  • dp数组如何初始化

        int dp[MAX_N + 1] = {0};

        dp[0] = 1;

  • 确定遍历顺序

        从前往后

  • 举例推导dp数组(用于检验)

代码实现:

#include <stdio.h>

#define MAX_N 18
int dp[MAX_N + 1] = {0};

int main(int argc, char *argv[]) {
    int n;
    scanf("%d", &n);
    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];
        }
    }
    printf("%d\n", dp[n]);
    return 0;
}

2.5. 循环

2.6. 传球游戏

动规五步曲:

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

        dp[j][i]:传了j轮球,球在第i个人手里的方法总数

  • 确定递推公式(容斥原理)

        容斥原理:dp[j][i]全集包括:

                                      倒数第二轮时球在第i-1个人手里 + 倒数第二轮时球在第 i+1个人手里

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

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

  • dp数组如何初始化

        

  • 确定遍历顺序

        从前往后

  • 举例推导dp数组(用于检验)

代码实现:

#include <stdio.h>

#define MAX_N 30
#define MAX_M 30
int dp[MAX_N + 1][MAX_N + 1] = {0};

int main(int argc, char *argv[]) {
    int n, m;
    scanf("%d%d", &n, &m);
    dp[0][1] = 1;
    for (int j = 1; j <= m; j++) {
        for (int i = 2; i <= n - 1; i++) {
            dp[j][i] = dp[j - 1][i + 1] + dp[j - 1][i - 1];
        }
        //单独处理边界
        dp[j][1] = dp[j - 1][2] + dp[j - 1][n];
        dp[j][n] = dp[j - 1][1] + dp[j - 1][n - 1];
    }
    printf("%d\n", dp[m][1]);
    return 0;
}

2.7. Hanoi 双塔问题

动规五步曲:

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

  • 确定递推公式(容斥原理)

  • dp数组如何初始化

  • 确定遍历顺序

  • 举例推导dp数组(用于检验)

三:动态规划

3.1. 全面剖析:数字三角形问题

1. 斐波那契数

动规五部曲:

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

         一维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]中可以看出,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

代码实现:

//1) 动归第一种解法 时间复杂度:O(n)  空间复杂度:O(n)
int fib(int n) {
    if (n <= 1) {
        return n;
    }
    int *dp = malloc(sizeof(int) * (n + 1));
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    int ret = dp[n]; //防止内存泄漏
    free(dp);
    return ret;
}

//2) 动规第二种解法  时间复杂度:O(n)  空间复杂度:O(1)
int fib(int n) {
    if (n <= 1) {
        return n;
    }
    int dp[2];
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        int sum = dp[0] + dp[1];
        dp[0] = dp[1];
        dp[1] = sum;
    }
    return dp[1];
}

//3) 递归+记忆化解法
#define MAX_N 30
int arr[MAX_N + 1] = {0}; //优化:记忆化(防止大量重复运算,加快运行效率)
int fib(int n) {
    if (n <= 1) {
        return n;
    }
    if (arr[n]) {
        return arr[n];
    }
    arr[n] = fib(n - 1) + fib(n - 2);
    return arr[n];
}

2. 爬楼梯

动规五步曲:

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

一维dp数组保存递归的结果

dp[i]:爬到第i层楼梯,有dp[i]种方法

2. 确定递推公式

从dp[i]的定义可以看出,dp[i] 可以有两个方向推出来

首先是dp[i - 1],上i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶就是dp[i]了

还有就是dp[i - 2],上i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶就是dp[i]了

那么dp[i]就是 dp[i - 1]与dp[i - 2]之和!

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

3. dp数组如何初始化

dp[1] = 1

dp[2] = 2

4. 确定遍历顺序

从递推公式dp[i] = dp[i - 1] + dp[i - 2]中可以看出,遍历顺序一定是从前向后遍历的

5. 举例推导dp数组

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

代码实现:

//动规
int climbStairs(int n) {
    if (n <= 2) {
        return n;
    }
    int dp[3];
    dp[1] = 1; //上一层台阶
    dp[2] = 2; //上两层台阶
    for (int i = 3; i <= n; i++) {
        int sum = dp[1] + dp[2];
        dp[1] = dp[2];
        dp[2] = sum;
    }
    return dp[2];
}

//递归
#include <stdio.h>
#define MAX_N 45
int arr[MAX_N + 1] = {0}; //记忆化优化
int climbStairs(int n) {
    if (n <= 2) {
        return n;
    }
    if (arr[n])
        return arr[n];
    arr[n] = climbStairs(n - 1) + climbStairs(n - 2);
    return arr[n];
}

3. 使用最小花费爬楼梯

动规五步曲:

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

使用动态规划,就要有一个数组来记录状态,本题只需要一个一维数组dp[i]就可以了

dp[i]的定义:第i个台阶所花费的最少体力为dp[i]

2. 确定递推公式

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

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

一定是选最小的,所以dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];

3. dp数组如何初始化

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

4. 确定遍历顺序

因为是模拟台阶,而且dp[i]又dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了

5. 举例推导dp数组

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

代码实现:

#define min(a, b)  ((a) > (b) ? (b) : (a))
int minCostClimbingStairs(int* cost, int costSize) {
    int *dp = malloc(sizeof(int) * (costSize + 1));
    dp[0] = dp[1] = 0;
    for (int i = 2; i <= costSize; i++) {
        dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
    }
    return dp[costSize];
}

4. 不同路径

动规五步曲:

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 - 1][j] 表示啥,是从(0, 0)的位置到(i - 1, j)有几条路径,dp[i][j - 1]同理

那么很自然,dp[i][j] =  dp[i - 1][j] + dp[i][j - 1],因为dp[i][j]只有这两个方向过来

3. dp数组的初始化

p[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 - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。

5. 举例推导dp数组

代码实现:

int uniquePaths(int m, int n) {
    //动态创建一个二维路径答案表
    int **dp = (int **)malloc(sizeof(int *) * m);
    for (int i = 0; i < m; i++) {
        dp[i] = (int *)malloc(sizeof(int) * 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];
}

5. 不同路径 II

动规五步曲:

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]

(i, j)如果就是障碍的话应该就保持初始状态(初始状态为0)

//当(i, j)没有障碍的时候,再推导dp[i][j]
if (obstacleGrid[i][j] == 0) {
    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}

3. dp数组如何初始化

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

4. 确定遍历顺序

从左到右一层一层遍历

5. 举例推导dp数组

拿示例1来举例如题:


对应的dp table 如图:

代码实现:

6. 整数拆分

动规五步曲:

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

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

相关文章

招投标信息可以用CRM系统来查看吗?

对于B2B企业来说获客难、获客成本高是共识。做大客户的企业通过招投标获取商机是一个重要获客途径&#xff0c;然而传统方式管理招投标信息问题很多&#xff0c;例如资料丢失、手工录入出错、信息分散、信息查找费时费力。为了解决这些难题小编推荐CRM系统&#xff0c;CRM系统需…

非参数估计与参数估计的区别,以及详细列举了常用的非参数估计方法和参数估计方法,一网打尽非参数估计与参数估计!!!

文章目录 前言一、非参数估计与参数估计的区别二、常用的非参数估计方法三、常用的参数估计方法总结 前言 非参数估计和参数估计是统计学中的两种不同的估计方法。 一、非参数估计与参数估计的区别 参数估计是指&#xff0c;对于已知分布形式的数据&#xff0c;根据样本数据…

WinEdt打开.tex文件显示error reading错误

原因&#xff1a; 是因为.tex文件中包含了utf-8字符&#xff0c;而在打开的时候并没有指明utf-8打开方式 解决方法 在WinEdt中&#xff0c;【File】-【Open】&#xff08;或使用快捷键CtrlO&#xff09;&#xff0c;在弹出的打开对话框中&#xff0c;右下角【文件名】右侧有…

全面探讨HTTP协议从0.9到3.0版本的发展和特点

前言&#xff1a; 最近的几场面试都问到了http的相关知识点&#xff0c;博主在此结合书籍和网上资料做下总结。本篇文章讲收录到秋招专题&#xff0c;该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出&#xff0c;对大佬有帮…

EI期刊论文复现:考虑电动汽车可调度潜力的充电站两阶段市场投标策略程序代码!

本程序代码参考EI期刊论文《考虑电动汽车可调度潜力的充电站两阶段市场投标策略》&#xff0c;程序中基于历史数据评估可调度潜力&#xff0c;由联合报价模型确定节点边际电价&#xff0c;作为报价的参考&#xff0c;包含个体竞价模式&#xff0c;纳什博弈竞价&#xff0c;算例…

PC8231(CC/CV)5V/2.4A同步降压芯片 频率可调 限流欠压补偿

一&#xff0e;概述 PC8231 是一款同步降压转换器&#xff0c; 该转换器可驱动输出 2.4A 负载电流。 设计允许 PC8231 在 9V 到40V 宽输入电压范围内工作。通过将 COMP/EN 引脚逻辑电平拉低来实现外部关断功能&#xff0c;并进入待机模式。外部补偿使反馈控制环路具有良好的线…

相机内存卡照片删除怎么恢复?没有备份可这样操作

在使用相机时&#xff0c;不小心删除了重要的照片可能是每位摄影爱好者的噩梦。然而&#xff0c;通过一些恢复方法&#xff0c;我们有机会挽救被删除的照片。本文将详细介绍相机内存卡照片删除恢复的方法。 图片来源于网络&#xff0c;如有侵权请告知 如果您误删了相机内存卡中…

网络篇---第二篇

系列文章目录 文章目录 系列文章目录前言一、说说 TCP 与 UDP 的区别,以及各自的优缺点二、说一下 HTTP 和 HTTPS 的区别三、说说HTTP、TCP、Socket 的关系是什么?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,…

在NAS上部署.NET版本的WOL远程开机服务

在本文中&#xff0c;我们将以部署基于.NET的WOL远程开机服务为例&#xff0c;详细介绍如何利用Docker技术在群辉部署ASP.NET服务。同时&#xff0c;我们还将展示如何对原有的控制台WOL进行改造&#xff0c;以及如何使用SignAuthorization简易URL验签类库。文章相关的代码开源地…

卤素灯和白炽灯哪个更护眼?精选高品质的护眼台灯

如果是放在以前&#xff0c;我觉得卤素灯会比白炽灯会眼一点。不过在如今这个高速发展的时代&#xff0c;灯源的迭代也经历了一轮又一轮&#xff0c;对于目前来说最护眼的还是LED护眼台灯 因为卤素灯和白炽灯产生的光线包含大量的红外线和紫外线&#xff0c;并且具有较高的亮度…

python树的孩子链存储结构

树的孩子链存储结构是一种树的存储方式&#xff0c;它使用孩子兄弟表示法来表示树的结构。在这种存储结构中&#xff0c;树的每个节点都有一个指向其第一个孩子的指针和一个指向其下一个兄弟的指针。这样&#xff0c;可以通过这些指针来表示树的层次结构和节点之间的关系。 具…

前端项目部署自动检测更新后通知用户刷新页面(前端实现,技术框架vue、js、webpack)——方案一:编译项目时动态生成一个记录版本号的文件

前言 当我们重新部署前端项目的时候&#xff0c;如果用户一直停留在页面上并未刷新使用&#xff0c;会存在功能使用差异性的问题&#xff0c;因此&#xff0c;当前端部署项目后&#xff0c;需要提醒用户有去重新加载页面。 技术框架 vue、js、webpack 解决方案 编译项目时动…

C#、.net、asp.net 超快超简单(一看就会)将redis添加到自己的项目中

背景&#xff1a;凌晨两点&#xff0c;隔壁楼情侣闹得欢&#xff0c;本单身狗不服气&#xff0c;决定总结一下今晚添加到项目的redis。 我的使用场景&#xff1a;asp.net core web apivue3的项目中数据库的权限表是最经常读取的&#xff0c;所以权限表中的数据放到redis中最为…

java Swing UI设置统一字体大小

编写一个遍历组件设置字体大小的方法 public static void setUIFont() {Font f new Font("宋体", Font.PLAIN, 18);String names[] {"Label", "CheckBox", "PopupMenu", "MenuItem", "CheckBoxMenuItem", &quo…

基于springboot+Web实现社区医院管理服务系统项目【项目源码+论文说明】

基于springbootWeb实现社区医院管理服务系统演示 摘要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括社区医院管理服务系统的网络应用&#xff0c;在外国线上管理系统已经是很普遍的方式&#xff0c;不过国内的管理系统可…

SAP是什么公司,开发什么系统软件?

SAP 是公司原德语名称 Systemanalyse Programmentwicklung 的首字母缩写&#xff0c;意思是系统分析程序开发 (System Analysis Program Development) 。现在&#xff0c;公司的注册名称为 SAP SE&#xff0c;其中 SE 代表 societas Europaea&#xff0c;是指根据欧盟公司法注册…

有关循环依赖和三级缓存的这些问题,你都会么?(面试常问)

一、什么是循环依赖 大家平时在写业务的时候应该写过这样的代码。 其实这种类型就是循环依赖&#xff0c;就是AService 和BService两个类相互引用。 二、三级缓存可以解决的循环依赖场景 如上面所说&#xff0c;大家平时在写这种代码的时候&#xff0c;项目其实是可以起来的&am…

leetcode:有效的括号

题目描述 题目链接&#xff1a;20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 题目分析 题目给了我们三种括号&#xff1a;&#xff08;&#xff09;、{ }、[ ] 这里的匹配包括&#xff1a;顺序匹配和数量匹配 最优的思路就是用栈来解决&#xff1a; 括号依次入栈…

Java核心知识点整理大全17-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

vue 中 js 金额数字转中文

参考&#xff1a;js工具函数之数字转为中文数字和大写金额_js封装工具类函数金额大写-CSDN博客 我使用的框架vol.core。 客户需求要将录入框的金额数字转换成中文在旁边显示&#xff0c;换了几种函数&#xff0c;最终确定如下函数 function changeToChineseMoney(Num) {//判断…