矩阵快速幂及应用实战[C/C++]

矩阵快速幂

矩阵快速幂可以用来优化递推问题,如状态机DP,需要一丢丢线性代数里面矩阵的概念,只需要知道简单的矩阵乘法,结合我们普通的二分快速幂就能很快的掌握矩阵快速幂。

问题引入

三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。

对于这种递推入门题目,相信只要对于编程有着一定了解的人都能够很快的解决掉。

假如我们用传统递推
f ( 0 ) = 1 , f ( 1 ) = 1 , f ( 2 ) = 2 f ( n ) = f ( n − 1 ) + f ( n − 2 ) + f ( n − 3 ) \begin{array}{c} f(0) = 1 , f(1) = 1 , f(2) = 2\\ f(n) = f(n-1) + f(n - 2) + f(n - 3) \end{array} f(0)=1,f(1)=1,f(2)=2f(n)=f(n1)+f(n2)+f(n3)

const int MOD = 1e9 + 7;
int dp[1000001];int waysToStep(int n) {memset(dp , 0 , sizeof(dp));dp[0] = 1, dp[1] = 1 , dp[2] = 2;for(int i = 3 ; i <= n ; i++)dp[i] = ((long long)dp[i - 3] + dp[i - 2] + dp[i - 1]) % MOD;return dp[n];}

时间复杂度:O(N) 空间复杂度:O(N)

因为每次状态都由前三个状态转移过来,如果用滚动数组优化

const int MOD = 1e9 + 7;int waysToStep(int n) {int dp0 = 1, dp1 = 1 , dp2 = 2;if(n <= 1) return 1;if(n == 2) return 2;for(int i = 3 ; i <= n ; i++){int newdp = ((long long)dp0 + dp1 + dp2) % MOD;dp0 = dp1 , dp1 = dp2 , dp2 = newdp;}return dp2;}

空间复杂度优化到了O(1),时间复杂度仍为O(N)

到滚动数组优化这一步对于大多数初学者来说已经很不错了,如果我们想更进一步呢?

我们重新分析递推公式
f ( 0 ) = 1 , f ( 1 ) = 1 , f ( 2 ) = 2 f ( n ) = f ( n − 1 ) + f ( n − 2 ) + f ( n − 3 ) \begin{array}{c} f(0) = 1 , f(1) = 1 , f(2) = 2\\ f(n) = f(n-1) + f(n - 2) + f(n - 3) \end{array} f(0)=1,f(1)=1,f(2)=2f(n)=f(n1)+f(n2)+f(n3)

递推公式到向量计算

第一步

我们尝试把递推公式写成矩阵乘上一个列向量的形式,如下:

( f ( n ) ? ? ) = ( 1 1 1 ? ? ? ? ? ? ) ( f ( n − 1 ) f ( n − 2 ) f ( n − 3 ) ) \begin{pmatrix} f(n)\\ ?\\ ? \end{pmatrix} =\begin{pmatrix} 1 & 1 & 1 \\ ? & ? & ? \\ ? & ? & ? \end{pmatrix} \begin{pmatrix} f(n - 1)\\ f(n - 2) \\ f(n - 3) \end{pmatrix} f(n)?? = 1??1??1?? f(n1)f(n2)f(n3)

第二步

接着尝试填充?部分

( f ( n ) f ( n − 1 ) f ( n − 2 ) ) = ( 1 1 1 ? ? ? ? ? ? ) ( f ( n − 1 ) f ( n − 2 ) f ( n − 3 ) ) \begin{pmatrix} f(n)\\ f(n - 1)\\ f(n - 2) \end{pmatrix} =\begin{pmatrix} 1 & 1 & 1 \\ ? & ? & ? \\ ? & ? & ? \end{pmatrix} \begin{pmatrix} f(n - 1)\\ f(n - 2) \\ f(n - 3) \end{pmatrix} f(n)f(n1)f(n2) = 1??1??1?? f(n1)f(n2)f(n3)

第三步

补充矩阵中的部分,就得到了:

( f ( n ) f ( n − 1 ) f ( n − 2 ) ) = ( 1 1 1 1 0 0 0 1 0 ) ( f ( n − 1 ) f ( n − 2 ) f ( n − 3 ) ) \begin{pmatrix} f(n)\\ f(n - 1)\\ f(n - 2) \end{pmatrix} =\begin{pmatrix} 1 & 1 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} f(n - 1)\\ f(n - 2) \\ f(n - 3) \end{pmatrix} f(n)f(n1)f(n2) = 110101100 f(n1)f(n2)f(n3)

第四步

你以为到这里就结束了?我们在该式子的基础上带入n - 1作为变量,则有:

( f ( n − 1 ) f ( n − 2 ) f ( n − 3 ) ) = ( 1 1 1 1 0 0 0 1 0 ) ( f ( n − 2 ) f ( n − 3 ) f ( n − 4 ) ) \begin{pmatrix} f(n - 1)\\ f(n - 2)\\ f(n - 3) \end{pmatrix} =\begin{pmatrix} 1 & 1 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} f(n - 2)\\ f(n - 3) \\ f(n - 4) \end{pmatrix} f(n1)f(n2)f(n3) = 110101100 f(n2)f(n3)f(n4)

第五步

我们把第四步中的式子带入到第三步中,就会得到

( f ( n ) f ( n − 1 ) f ( n − 2 ) ) = ( 1 1 1 1 0 0 0 1 0 ) ( 1 1 1 1 0 0 0 1 0 ) ( f ( n − 2 ) f ( n − 3 ) f ( n − 4 ) ) \begin{pmatrix} f(n)\\ f(n - 1)\\ f(n - 2) \end{pmatrix} =\begin{pmatrix} 1 & 1 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} 1 & 1 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} f(n - 2)\\ f(n - 3) \\ f(n - 4) \end{pmatrix} f(n)f(n1)f(n2) = 110101100 110101100 f(n2)f(n3)f(n4)

第六步

我们不断地迭代下去就会有这样一个式子:

( f ( n ) f ( n − 1 ) f ( n − 2 ) ) = ( 1 1 1 1 0 0 0 1 0 ) n − 2 ( f ( 2 ) f ( 1 ) f ( 0 ) ) \begin{pmatrix} f(n)\\ f(n - 1)\\ f(n - 2) \end{pmatrix} =\begin{pmatrix} 1 & 1 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{pmatrix}^{n-2} \begin{pmatrix} f(2)\\ f(1) \\ f(0) \end{pmatrix} f(n)f(n1)f(n2) = 110101100 n2 f(2)f(1)f(0)
我们发现f(n)的计算还可以通过计算出一个已知矩阵的n - 2次幂与一个列向量的乘积来获取。那么这样的计算方式可以令我们算法的执行效率得到提高吗?

对于两个M阶矩阵做乘积,其时间复杂度为O(M^3),进行n - 2次,那么时间复杂度就是O(M^3 * n),似乎与我们的传统递归相比还要慢上常数阶,于是这就引出了我们今天的主题矩阵快速幂

普通二分快速幂

关于二分快速幂的介绍在笔者的另一篇博客有详细介绍及证明二分快速幂和快读快写模板【C++】-CSDN博客

对于我们快速求a ^ b % p,我们可以不断地二分为(a ^ 2) ^ (b / 2) % p…

如果出现b为奇数,就使得我们最终的返回值ans(ans初始为1)乘上a,当指数为0的时候循环执行完毕,此时ans就是我们的答案。

同样的思想也可以用于矩阵的幂运算中。

代码如下

inline long long quickPower(int a, int b, int p)
{long long ans = 1;while (b){if (b & 1){ans = ans * a % p;}a = a * a % p;b /= 2;}return ans;
}

矩阵二分快速幂

由普通二分快速幂对矩阵做推广,可有如下递归式
A n = { I n = 0 ( A n − 1 2 ) 2 × A n 为奇数 ( A n 2 ) 2 × A n 为非零偶数 A^{n} = \left\{\begin{matrix} I\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ n=0 \\ (A^{\frac{n-1}{2}})^2\times A \ \ \ \ \ \ \ n为奇数 \\ (A^{\frac{n}{2}})^2\times A \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ n为非零偶数 \\ \end{matrix}\right. An= I                     n=0(A2n1)2×A       n为奇数(A2n)2×A                 n为非零偶数
那么我们只需要把普通二分快速幂模板中整数乘法更换成矩阵乘法即可。

矩阵类的定义

struct Matrix
{int m[101][101];Matrix(){memset(m, 0, sizeof(m));}
};

矩阵乘法的运算符重载

Matrix operator*(const Matrix &x, const Matrix &y)
{Matrix ret;for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)for (int k = 1; k <= n; k++)ret.m[i][j] = (ret.m[i][j] + (x.m[i][k] * y.m[k][j]) % MOD) % MOD;return ret;
}

矩阵快速幂模板

Matrix MatrixQuickPower(const Matrix &A, int k)
{Matrix res;for (int i = 1; i <= n; i++)res.m[i][i] = 1; // 单位矩阵while (k){if (k & 1)res = res * A;A = A * A;k >>= 1;}return res;
}

矩阵快速幂就是对普通二分快速幂的基础上,将运算对象更改为了矩阵罢了。

矩阵乘法的常数级优化

我们发现矩阵乘法这里y每次访问m[k][j]寻址需要跳过一整行,对性能其实是有一定影响的,我们可以把第二层循环和第三层循环进行交换

Matrix operator*(const Matrix &x, const Matrix &y)
{Matrix ret;for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)for (int k = 1; k <= n; k++)ret.m[i][j] = (ret.m[i][j] + (x.m[i][k] * y.m[k][j]) % MOD) % MOD;return ret;
}

则有

Matrix operator*(const Matrix &x, const Matrix &y)
{Matrix ret;for (int i = 1; i <= n; i++)for (int k = 1; k <= n; k++)for (int j = 1; j <= n; j++)ret.m[i][j] = (ret.m[i][j] + (x.m[i][k] * y.m[k][j]) % MOD) % MOD;return ret;
}

这样既不影响结果,又降低了寻址消耗。

矩阵快速幂在状态机DP中的应用

如果你学习过数字逻辑电路,相信对于时序电路中的有限状态机不会陌生,没有学过也没有关系,因为学了也不会状态机DP,做算法题早晚都要面对的

其实虽然状态机DP在动态规划中算是一类难度不低的问题,但是只要多做几道题就会很快的掌握其套路,相较于背包问题,难度低了不少,因为套路更容易掌握。

下面详解一道题,留下另一道题供读者练手。

OJ题目精讲

935. 骑士拨号器

象棋骑士有一个独特的移动方式,它可以垂直移动两个方格,水平移动一个方格,或者水平移动两个方格,垂直移动一个方格(两者都形成一个 L 的形状)。

象棋骑士可能的移动方式如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们有一个象棋骑士和一个电话垫,如下所示,骑士只能站在一个数字单元格上(即蓝色单元格)。

img

给定一个整数 n,返回我们可以拨多少个长度为 n 的不同电话号码。

你可以将骑士放置在任何数字单元格上,然后你应该执行 n - 1 次移动来获得长度为 n 的号码。所有的跳跃应该是有效的骑士跳跃。

因为答案可能很大,所以输出答案模 109 + 7.

对于长度为n的电话号码,每个位置有10种情况,如果没有题目中的限制,我们通过简单的组合数学就可以解决.

但现在每个位置可以移动的方式都给出了限制,也就是说在每个位置可以抵达的下一个位置是确定且有限的.

我们如果把每个位置都看做成是一种状态,那么我们有如下的状态转移关系:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们定义状态dp[i][j]为第i次移动后在位置j的情况数,那么我们有如下状态转移方程:
d p [ i ] [ j ] = ∑ d p [ i − 1 ] [ k ] , 其中 j 可由 k 转移 dp[i][j] = \sum dp[i-1][k],其中j可由k转移 dp[i][j]=dp[i1][k],其中j可由k转移

非矩阵快速幂解法

我们打表列出每个位置的的前驱状态,然后执行状态转移方程,最后对dp[n][i]进行累加即可

class Solution {
public:
const int MOD = 1e9 + 7;
vector<vector<int>> pre{{4 , 6} , {6 , 8} , {7 , 9} , {4 , 8} , {0 , 3 , 9} , {} , {0 , 1 , 7} , {2 , 6} , {1 , 3} , {2 , 4}
};int knightDialer(int n) {vector<vector<int>> dp(n + 1 , vector<int>(10));for(int i = 0 ; i < 10 ; i++)dp[1][i] = 1;for(int i = 2 ; i <= n ; i++){for(int j = 0 ; j < 10 ; j++){for(auto x : pre[j])dp[i][j] = (dp[i - 1][x] + dp[i][j]) % MOD; }}long long ret = 0;for(int i = 0 ; i < 10 ; i++)ret = (ret + dp[n][i]) % MOD;return ret;}
};
滚动数组优化

由于每个状态只与上一次状态有关,所以我们还可以优化二维为一维,代码如下:

class Solution {
public:
const int MOD = 1e9 + 7;
vector<vector<int>> pre{{4 , 6} , {6 , 8} , {7 , 9} , {4 , 8} , {0 , 3 , 9} , {} , {0 , 1 , 7} , {2 , 6} , {1 , 3} , {2 , 4}
};int knightDialer(int n) {vector<int> dp(10);for(int i = 0 ; i < 10 ; i++)dp[i] = 1;for(int i = 2 ; i <= n ; i++){vector<int> newdp(10);for(int j = 0 ; j < 10 ; j++){for(auto x : pre[j])newdp[j] = (dp[x] + newdp[j]) % MOD; }dp = newdp;}long long ret = 0;for(int i = 0 ; i < 10 ; i++)ret = (ret + dp[i]) % MOD;return ret;}
};
矩阵快速幂解法

其实我们对于我们矩阵快速幂优化递推问题而言,只要提前写出矩阵A的行列式即可。对于本题我们分析
n e w d p [ 0 ] = d p [ 4 ] + d p [ 6 ] n e w d p [ 1 ] = d p [ 6 ] + d p [ 8 ] n e w d p [ 2 ] = d p [ 7 ] + d p [ 9 ] . . . \begin{array}{c} newdp[0] = dp[4]+dp[6]\\ newdp[1] = dp[6]+dp[8]\\ newdp[2] = dp[7]+dp[9]\\ ... \end{array} newdp[0]=dp[4]+dp[6]newdp[1]=dp[6]+dp[8]newdp[2]=dp[7]+dp[9]...
对于我们的10x10矩阵A的行列式可以很容易的计算出,于是我们的递推公式的矩阵表示为:
$$
\begin{pmatrix}
dpn(0)\
dpn(1)\
dpn(2)\
dpn(3)\
dpn(4)\
dpn(5)\
dpn(6)\
dpn(7)\
dpn(8)\
dpn(9)
\end{pmatrix} =\begin{pmatrix}
{0, 0, 0, 0, 1, 0, 1, 0, 0, 0}\
{0, 0, 0, 0, 0, 0, 1, 0, 1, 0}\
{0, 0, 0, 0, 0, 0, 0, 1, 0, 1}\
{0, 0, 0, 0, 1, 0, 0, 0, 1, 0}\
{1, 0, 0, 1, 0, 0, 0, 0, 0, 1}\
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}\
{1, 1, 0, 0, 0, 0, 0, 1, 0, 0}\
{0, 0, 1, 0, 0, 0, 1, 0, 0, 0}\
{0, 1, 0, 1, 0, 0, 0, 0, 0, 0}\
{0, 0, 1, 0, 1, 0, 0, 0, 0, 0}

\end{pmatrix}^{n} \begin{pmatrix}
dp(0)\
dp(1)\
dp(2)\
dp(3)\
dp(4)\
dp(5)\
dp(6)\
dp(7)\
dp(8)\
dp(9)
\end{pmatrix}
$$
我们矩阵运算时间复杂度为O(103),执行logn次,这样我们的时间复杂度就降到了**O(103 * logn)**

代码如下:

const int MOD = 1e9 + 7;struct Matrix
{long long m[10][10];Matrix(){memset(m, 0, sizeof(m));}Matrix(int x) :m{{0, 0, 0, 0, 1, 0, 1, 0, 0, 0},{0, 0, 0, 0, 0, 0, 1, 0, 1, 0},{0, 0, 0, 0, 0, 0, 0, 1, 0, 1},{0, 0, 0, 0, 1, 0, 0, 0, 1, 0},{1, 0, 0, 1, 0, 0, 0, 0, 0, 1},{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 1, 0, 0},{0, 0, 1, 0, 0, 0, 1, 0, 0, 0},{0, 1, 0, 1, 0, 0, 0, 0, 0, 0},{0, 0, 1, 0, 1, 0, 0, 0, 0, 0}}{}
};
Matrix A, dp;Matrix operator*(const Matrix& x, const Matrix& y)
{Matrix ret;for (int i = 0; i < 10; i++)for (int k = 0; k < 10; k++)for (int j = 0; j < 10; j++)ret.m[i][j] = (ret.m[i][j] + (x.m[i][k] * y.m[k][j]) % MOD) % MOD;return ret;
}
Matrix MatrixQuickPower(Matrix& A, int k)
{Matrix res;for (int i = 0; i < 10; i++)res.m[i][i] = 1; // 单位矩阵while (k){if (k & 1)res = res * A;A = A * A;k >>= 1;}return res;
}
int init(int n)
{A = Matrix(1);for (int i = 0; i < 10; i++)dp.m[i][0] = 1;Matrix dpn = MatrixQuickPower(A, n - 1) * dp;int ret = 0;for (int i = 0; i < 10; i++)ret = (ret + dpn.m[i][0]) % MOD;return ret;
}
class Solution {
public:int knightDialer(int n) {return init(n);}
};

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

遥遥领先

这里省事直接套模板了,有很多拷贝是可以优化掉的。就不演示了(懒x_x)

练习题OJ链接

这道题留给大家练习

552. 学生出勤记录 II - 力扣(LeetCode)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【海思SS528 | VDEC】MPP媒体处理软件V5.0 | VDEC的使用总结

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

Python语言学习笔记之五(Python代码注解)

本课程对于有其它语言基础的开发人员可以参考和学习&#xff0c;同时也是记录下来&#xff0c;为个人学习使用&#xff0c;文档中有此不当之处&#xff0c;请谅解。 注解与注释是不一样的&#xff0c;注解有更广泛的应用&#xff1b; 通过注解与注释都能提高代码的可读性和规…

RabbitMQ消息模型之Work Queues

Work Queues Work Queues&#xff0c;也被称为&#xff08;Task Queues&#xff09;&#xff0c;任务模型&#xff0c;也是官网给出的第二个模型&#xff0c;使用的交换机类型是直连direct&#xff0c;也是默认的交换机类型。当消息处理比较耗时的时候&#xff0c;可能生产消息…

Altium Designer学习笔记8

创建原理图元件&#xff1a; 画出原理图&#xff1a; 根据规则书画出原理图&#xff1a; 根据规则书画出封装图&#xff1a; 参照&#xff1a; 确认下过孔的内径和外径的最小允许值。

GoLang切片

一、切片基础 1、切片的定义 切片&#xff08;Slice&#xff09;是一个拥有相同类型元素的可变长度的序列它是基于数组类型做的一层封装它非常灵活&#xff0c;支持自动扩容切片是一个引用类型&#xff0c;它的内部结构包含地址、长度和容量声明切片类型的基本语法如下&#…

关于图像识别,你不得不知的三大要点

图像识别的重要性 图像识别不仅可以加速处理繁琐的任务&#xff0c;而且还可以比人工图像检查更快速或更准确地处理图像。图像识别是应用于诸多领域的关键技术&#xff0c;也是深度学习应用的主要驱动因素&#xff0c;如&#xff1a; 视觉检查&#xff1a;在制造过程中识别零部…

初刷leetcode题目(11)——数据结构与算法

&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️…

Linux:创建进程 -- fork,到底是什么?

相信大家在初学进程时&#xff0c;对fork函数创建进程一定会有很多的困惑&#xff0c;比如&#xff1a; 1.fork做了什么事情?? 2.为什么fork函数会有两个返回值?3.为什么fork的两个返回值&#xff0c;会给父进程谅回子进程pid&#xff0c;给子进程返回0?4.fork之后:父子进…

Unity 引擎宣布:自 2024 年起,开发者需支付费用!

Unity引擎宣布的新的收费模式&#xff0c;从2024年1月1日开始&#xff0c;根据游戏的安装量来对开发者进行收费。具体来说&#xff0c;每次游戏被下载时&#xff0c;UnityRuntime也会被安装&#xff0c;因此可能会产生额外的费用。对于开发者来说&#xff0c;需要注意以下几点&…

yml转properties工具

目前搜索到的大部分代码都存在以下问题&#xff1a; 复杂结构解析丢失解析后顺序错乱 所以自己写了一个&#xff0c;经过不充分测试&#xff0c;基本满足使用。可以直接在线使用 在线地址 除了yml和properties互转之外&#xff0c;还可以生成代码、sql转json等&#xff0c;可…

嵌入式Linux学习(2)——经典CAN介绍(上)

目录 一. CAN与ISO-OSI Model 二. CAN通信 2.1 接线方式 2.1.1 闭环网络 2.1.2 开环网络 2.2 收发流程 2.2.1 发送 2.2.2 接收 三. CAN BUS访问与仲裁 3.1 “线与”机制​ 3.2 仲裁机制 REF CAN&#xff08;Controller Area Network&#xff09;总线协议是由 BOSC…

【蓝桥杯选拔赛真题26】C++字符串逆序 第十三届蓝桥杯青少年创意编程大赛C++编程选拔赛真题解析

目录 C/C++字符串逆序 一、题目要求 1、编程实现 2、输入输出 二、算法分析

MySQL 中的锁(三)

8.7. 死锁和空间锁 一般来说&#xff0c;只要有并发和加锁这两种情况的共同加持下&#xff0c;都会有死锁的身影。 死锁的具体成因&#xff0c;借用我们在并发编程中的内容&#xff1a; 8.7.1. 死锁 8.7.1.1. 概念 是指两个或两个以上的进程在执行过程中&#xff0c;由于竞…

JSON.stringify方法详解 后端接受JSON数据格式

1、方法定义&#xff1a;JSON.stringify(value, replacer, space) 参数说明&#xff1a; value&#xff1a;js对象 replacer&#xff1a;替换对象&#xff0c;可以是一个方法、对象或数组&#xff0c;将value按照替换规则展示。 space&#xff1a;填充参数&#xff0c;可以是数…

Linux常用命令——rm 命令

文章目录 Linux系统中的rm命令是一个非常强大且危险的工具&#xff0c;用于删除文件和目录。由于其具有不可逆的特性&#xff0c;了解其参数和正确使用非常重要。 1. 基本用法 rm命令的基本格式是rm [选项] 文件或目录。不带任何选项时&#xff0c;rm命令仅删除文件。 示例&a…

数据结构-二叉树(2)

3.4堆的应用 3.4.1 堆排序 堆排序即利用堆的思想来进行排序&#xff0c;总共分为两个步骤&#xff1a; 1. 建堆 1.升序&#xff1a;建大堆&#xff1b; 2.降序&#xff1a;建小堆。 2. 利用堆删除思想来进行排序 这种写法有两个缺点&#xff1a; 1、先有一个堆的数据结构 …

springboot整合websocket

websocket和传统http协议 http 概念 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一种用于传输超文本数据的应用层协议。它是基于TCP/IP协议来传输数据的&#xff0c;是Web浏览器和Web服务器之间进行数据交换的标准协议。 HTTP协议的主要特点包括&#xff1a;…

JAVA小游戏“飞翔的小鸟”

第一步是创建项目 项目名自拟 第二步创建个包名 来规范class 再创建一个包 来存储照片 如下&#xff1a; 代码如下&#xff1a; package game; import java.awt.*; import javax.swing.*; import javax.imageio.ImageIO; public class Bird { Image image; in…

YOLOv8改进实战 | 更换主干网络Backbone(六)之轻量化模型VanillaNet进阶篇

前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不…

Linux(11):Linux 账号管理与 ACL 权限设定

Linux 的账号与群组 每个登入的使用者至少都会取得两个 ID&#xff0c;一个是使用者 ID(User ID &#xff0c;简称UID)、一个是群组ID (Group ID &#xff0c;简称GID)。 Linux系统上面的用户如果需要登入主机以取得 shell 的环境来工作时&#xff0c;他需要如何进行呢? 首先…