第一章 基础算法(二)——高精度,前缀和与差分

文章目录

    • 高精度运算
      • 高精度加法
      • 高精度减法
      • 高精度乘法
      • 高精度除法
    • 前缀和
      • 二维前缀和
    • 差分
      • 二维差分
    • 高精度练习题
      • 791. 高精度加法
      • 792. 高精度减法
      • 793. 高精度乘法
      • 794. 高精度除法
    • 前缀和练习题
      • 795. 前缀和
      • 796. 子矩阵的和
    • 差分练习题
      • 797. 差分
      • 798. 差分矩阵

高精度运算

两个大数做运算,位数一般是1e6

大整数的存储,数组的低位存储整数的低位,类似于小端存储

高精度加法

Ai + Bi + t:每一位相加,再加上进位,一开始进位为0
t变量保存AiBi相加的结果,不过需要先判断这两个数是否存在,一开始t0
AB的每一位数都加完后,还判断是否还有进位,即t是否为1,若有进位,最高位需要补上1

// C = A + B
vector<int> add(vector<int>& A, vector<int>& B)
{
	vector<int> C;
	int t = 0; // 进位
	for (int i = 0; i < A.size() || i < B.size(); ++i)
	{
		if (i < A.size()) t += A[i];
		if (i < B.size()) t += B[i];
		C.push_back(t % 10);
		t /= 10;
	}
	if (t) C.push_back(1);
	return C;
}

另外一种思路,默认将A作为更长的大整数,也就是当A的长度小于B的程度时,执行add(B, A)

// C = A + B
vector<int> add(vector<int>& A, vector<int>& B)
{
	vector<int> C;
	int t = 0; // 进位
	if (A.size() < B.size()) return add(B, A);
	for (int i = 0; i < A.size(); ++i)
	{
		t += A[i];
		if (i < B.size()) t += B[i];
		C.push_back(t % 10);
		t /= 10;
	}
	if (t) C.push_back(1);
	return C;
}

高精度减法

Ai - Bi - t:从最低位开始,每一位相减,再减去借位
若以上的值小于0,那么计算的结果为Ai - Bi - t + 10
若以上的值大于等于0,那么计算的结果为Ai - Bi - t
将以上的结果保存到t中,也就是每次计算的时候:t = A[i] - B[i] - t
对于最后的结果,可以用(t + 10) % 10处理:将t小于0以及t大于等于0的两种情况合并到一起

以上计算的前提是:A大于B。若A小于B, 则需要计算B - A。即保证被减数的绝对值大于减数

所以在进行计算前,需要比较两个数的大小:

  • 先比较长度,长度长的数更大
  • 若两数长度一样,那么从高位开始比较
    • A i A_i Ai != B i B_i Bi,则返回 A i A_i Ai > B i B_i Bi这个表达式的结果
  • 若循环走完,函数还没有返回,那么返回true,表示AB相等

以下模板只给出了两个正数相减的情况。若数字存在负数,此时可以转换为两数的绝对值相减或者相加,关于最后的符号问题,分情况讨论即可

需要注意的是:最后需要去除前导0

bool cmp(vector<int>& A, vector<int>& B)
{
    if (A.size() != B.size()) return A.size() > B.size();
    for (int i = A.size() - 1; i >= 0; --i)
        if (A[i] != B[i]) return A[i] > B[i];
    return true;
}

// 保证A > B
vector<int> sub(vector<int>& A, vector<int>& B)
{
    int t = 0;
    vector<int> C;
    for (int i = 0; i <= A.size(); ++i)
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    } 
    // 去除前导0
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

高精度乘法

注意:只有一个数是高精度的,另一个数比较小
A * blen(A) <= 10b <= 10000
b看成一个整体和A相乘,而不是Ab一位一位的相乘

t保存每一次b A i A_i Ai相乘的结果,同时加上进位,注意t同时也是进位,且t的初值为0
t += A[i] * bt / 10为下一次计算的进位,t % 10C需要保存的结果,保存的顺序从低位开始到高位

A n A_n An的每一位和b相乘完后,可能还留有进位,即t不为0,此时仍然需要对t进行% 10 / 10的操作,直到t0

可以通过以下具体例子,推演高精度乘法的过程
image.png

// C = A * b
vector<int> mul(vector<int>& A, int b)
{
	vector<int> C;
	int t = 0; // 进位
	
	for (int i = 0; i < A.size() || t; ++i)
	{
		if (i < A.size()) t += A[i] * b;
		C.push_back(t % 10);
		t /= 10;
	}
	while (C.size() > 1 && C.back() == 0) C.pop_back();
	return C;
}

注意:乘法运算结果,也需要去除前导0

高精度除法

同样,A为高精度,而b是较小的数

  1. 从最高位 A i A_i Ai开始,此时余数为0,将余数乘以10,加上 A i A_i Ai,作为新的被除数
  2. 将被除数除以b,商作为结果的第一位(最高位 ),保留被除数模b的余数
  3. 将余数乘以10,加上 A i − 1 A_{i-1} Ai1。得到新的被除数,商作为结果的第二位,保留除数模b的余数…
  4. 直到走到A的最低位,此时的余数为整个结果的余数

可以发现,余数和被除数之间存在着一种转换关系,这里用r表示余数与被除数
由于我们使用数组的低位保存大整数的低位,而除法运算中,我们每次得到的是结果的高位。并且整数的高位到数组的低位上,所以最后需要反转字符串。同时,需要去除前导0

// C = A / b
vector<int> div(vector<int>& A, int b, int &r)
{
	vector<int> C;
	r = 0;
	for (int i = A.size() - 1; i >= 0; --i)
	{
		r = r * 10 + A[i]; // 得到被除数
		C.push_back(r / b);
		r %= b;            // 得到余数
	}
	reverse(C.begin(), C.end());
	while (C.size() > 1 && C.back() == 0) C.pop_back();
	
	return C;
}

前缀和

数组 a n a_n an,前缀和 S i S_i Si就是累加 a 1 a_1 a1 a i a_i ai

如何求Si?
公式: S i S_i Si = S i − 1 S_{i-1} Si1 + a i a_i ai

作用?
快速的求出原数组中某一区间的和,sum[l, r] = S r S_r Sr - S l − 1 S_{l-1} Sl1

二维前缀和

公式: S i j S_{ij} Sij = a i j a_{ij} aij + S i − 1 , j S_{i-1,j} Si1,j + S i , j − 1 S_{i,j-1} Si,j1 - S i − 1 , j − 1 S_{i-1,j-1} Si1,j1


差分

给定数组 a n a_n an,构造 b n b_n bn数组使得 a n a_n an数组是 b n b_n bn数组的前缀和
b 1 b_1 b1 = a 1 a_1 a1 - a 0 a_0 a0
b 2 b_2 b2 = a 2 a_2 a2 - a 1 a_1 a1
b n b_n bn = a n a_n an - a n − 1 a_{n-1} an1,注意 a 0 a_0 a0的值为0,这是假设的
但是构建差分数组不使用以上方法,以上只是差分数组的性质。构建差分数组则是利用这一性质:

若现在有操作需要对[ a l a_l al, a r a_r ar]中的所有数加上c。此时可以不对 a n a_n an进行操作,而对其差分数组 b n b_n bn进行操作

因为 a n a_n an b n b_n bn的前缀和数组,若 b l b_l bl + c,那么 a l a_l al + c, a l + 1 a_{l+1} al+1 + c, a r a_r ar + c。因为 a r + 1 a_{r+1} ar+1不需要+c。因此 b r + 1 b_{r+1} br+1 - c,使得 a r + 1 a_{r+1} ar+1不变。这样操作就只用O(1)的时间完成了需要对 a n a_n an数组的O(n)操作

差分数组的构造,假定原矩阵 a n a_n an元素全为0,然后将 a i a_i ai插入到区间[i, i]中,此时修改 b i b_i bi b i b_i bi + a i a_i ai,修改 b i + 1 b_{i+1} bi+1 b i + 1 b_{i+1} bi+1 - a i a_i ai

对于差分,不需要考虑如何构造,只需要考虑如何更新即可。以上方法是一种特殊的更新,可以用于差分的构造

差分模板:

// 核心是insert操作,对原数组的某段区间加上某个值
void insert(int l, int r, int c)
{
	b[l] += c;
	b[r + 1] -= c;
}

至于原数组 a n a_n an怎么求,对差分数组 b n b_n bn用前缀和公式即可

二维差分

同样,构造即更新,所以先理解更新:
若给定一个二维矩阵,矩阵中ij列的元素用 a i j a_{ij} aij表示,现需要对矩阵中以[ x 1 x_1 x1, y 1 y_1 y1]为左上角,以[ x 2 x_2 x2, y 2 y_2 y2]为右下角中的所有元素加上某个值,要怎么做?

根据 a i j a_{ij} aij矩阵构造其差分矩阵 b i j b_{ij} bij,其中 a i j a_{ij} aij矩阵为 b i j b_{ij} bij矩阵的前缀和。
b x 1 , y 1 b_{x_1, y_1} bx1,y1 + c时, a i j a_{ij} aij矩阵中,满足i >= x 1 x_1 x1 && j >= y 1 y_1 y1的所有元素都变成: a i , j a_{i, j} ai,j + c。
而需要+ c的区间为[ x 1 x_1 x1, y 1 y_1 y1]到[ x 2 x_2 x2, y 2 y_2 y2],所以对于满足i >= x 2 x_2 x2 || j >= y 2 y_2 y2的元素,需要保持原样,现在它们的值为 a i , j a_{i, j} ai,j + c,需要修改为 a i , j a_{i, j} ai,j + c - c
此时需要修改差分数组, b x 2 + 1 , y 1 b_{x_2+1, y_1} bx2+1,y1 - c, b x 1 , y 2 + 1 b_{{x_1}, y_2+1} bx1,y2+1 - c, b x 2 + 1 , y 2 + 1 b_{x_2+1, y_2+1} bx2+1,y2+1 + c
此时该差分矩阵推导出的原矩阵中,以[ x 1 x_1 x1, y 1 y_1 y1]为左上角,以[ x 2 x_2 x2, y 2 y_2 y2]为右下角中的所有元素都 + c

二维差分模板:

void insert(int x1, int y1, int x2, int y2, int c)
{
	b[x1][y1] += c;
	b[x2 + 1][y1] -= c;
	b[x1][y2 + 1] -= c;
	b[x2 + 1][y2 + 1] += c;
}

image.png


高精度练习题

791. 高精度加法

791. 高精度加法 - AcWing题库
image.png

输入的处理:用string获取两个加数AB,将加数的低位放到数组的低下标处,高位放到数组的高下标处

用高精度加法模板进行加法运算

#include <iostream>
#include <string>
#include <vector>
using namespace std;

vector<int> add(vector<int>& A, vector<int>& B)
{
    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size() || i < B.size(); ++i) 
    {
        if (i < A.size()) t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }
    if (t) C.push_back(1);
    
    return C;
}

int main()
{
    string a, b;
    cin >> a >> b;
    vector<int> A, B;
    for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; --i) B.push_back(b[i] - '0');
    
    vector<int> C = add(A, B);
    for (int i = C.size() - 1; i >= 0; --i) printf("%d", C[i]);
    return 0;
}

792. 高精度减法

792. 高精度减法 - AcWing题库
image.png
image.png

我认为cmp的判断写得很巧妙,两个判断都是当不等于的时候,返回一个比较的结果
这样子处理的逻辑也更清晰
以及,当A < B时,为了不写花括号,y总甚至写了逗号表达式,怎么说,这样子处理也是不错的吧

#include <iostream>
#include <string>
#include <vector>
using namespace std;

string a, b;
vector<int> A, B;

bool cmp(vector<int>& A, vector<int>& B)
{
    if (A.size() != B.size()) return A.size() > B.size();
    for (int i = A.size() - 1; i >= 0; --i)
        if (A[i] != B[i]) return A[i] > B[i];
    return true;
}

// 保证A > B
vector<int> sub(vector<int>& A, vector<int>& B)
{
    int t = 0;
    vector<int> C;
    for (int i = 0; i <= A.size(); ++i)
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    } 
    // 去除前导0
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

int main()
{
    cin >> a >> b;
    for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; --i) B.push_back(b[i] - '0');
    vector<int> C;
    if(cmp(A, B)) C = sub(A, B);
    else C = sub(B, A), printf("-");
    
    for (int i = C.size() - 1; i >= 0; --i) printf("%d", C[i]);
    
    return 0;
}

793. 高精度乘法

793. 高精度乘法 - AcWing题库
image.png

#include <iostream>
#include <string>
#include <vector>
using namespace std;

string a;
vector<int> A;
int b;

vector<int> mul(vector<int>& A, int b)
{
    int t = 0;
    vector<int> C;
    for (int i = 0; i < A.size() || t; ++i)
    {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

int main()
{
    cin >> a >> b;
    for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
    auto C = mul(A, b);
    for (int i = C.size() - 1; i >= 0; --i) printf("%d", C[i]);
    return 0;
}

794. 高精度除法

794. 高精度除法 - AcWing题库
image.png

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;
vector<int> A;
string a;
int b, r;

vector<int> div(vector<int>& A, int b, int& r)
{
    r = 0;
    vector<int> C;
    for (int i = A.size() - 1; i >= 0; --i)
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    
    return C;
}

int main()
{
    cin >> a >> b;
    for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
    
    auto C = div(A, b, r);
    for (int i = C.size() - 1; i >= 0; --i) printf("%d", C[i]);
    printf("\n%d", r);
    
    return 0;
}

前缀和练习题

795. 前缀和

795. 前缀和 - AcWing题库
image.png
给定一个数组,获取该数组后,根据其询问的区间返回区间和
利用前缀和数组的预处理,从 a n a_n an数组得到 S n S_n Sn前缀和数组
当询问[l, r]的区间和时,只要返回 S r S_r Sr - S l − 1 S_{l-1} Sl1

#include <iostream>
using namespace std;

const int N = 1e6 + 10;
int a[N] = {0}, S[N] = {0};
int n,m;
int l,r;

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    
    for (int i = 1; i <= n; ++i) S[i] = S[i - 1] + a[i];
    
    while (m--)
    {
        scanf("%d%d", &l, &r);
        printf("%d\n", S[r] - S[l - 1]);
    }
    
    return 0;
}

796. 子矩阵的和

796. 子矩阵的和 - AcWing题库
image.png

利用二维前缀和的公式即可解题

#include <iostream>
using namespace std;

const int N = 1010;
int a[N][N] = {0}, S[N][N] = {0};
int n, m, q;
int x1, y1, x2, y2;

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    // 获取原矩阵
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%d", &a[i][j]);
    // 构建前缀和矩阵
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            S[i][j] = a[i][j] + S[i - 1][j] + S[i][j - 1] -S[i - 1][j - 1];
            
    // 处理询问
    while (q--)
    {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        printf("%d\n", S[x2][y2] - S[x2][y1 - 1] - S[x1 - 1][y2] + S[x1 - 1][y1 - 1]);
    }
    return 0;
}

差分练习题

797. 差分

797. 差分 - AcWing题库
image.png

题目输入原数组 a n a_n an,我们用特殊的更新构建其差分数组 b n b_n bn。对于原数组的区间操作,只要修改差分数组即可,最后根据差分数组使用前缀和公式推导原数组即可

#include <iostream>
using namespace std;

const int N = 1e6 + 10;
int a[N], b[N] = {0};
int n, m;
int l, r, c;

void insert(int l, int r, int c)
{
    b[l] += c;
    b[r + 1] -= c;
}

int main()
{
    scanf("%d%d", &n, &m);
    // 获取a数组
    for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    // 构造其差分数组
    for (int i = 0; i < n; ++i) insert(i, i, a[i]);
    
    while (m--)
    {
        scanf("%d%d%d", &l, &r, &c);
        insert(l - 1, r - 1, c);
    }
    
    // 推导a数组
    for (int i = 1; i < n; ++i) b[i] += b[i - 1];
    // 打印最终数组 
    for (int i = 0; i < n; ++i) printf("%d ", b[i]);
    return 0;
}

所以还可以这样解:

#include <iostream>
using namespace std;

const int N = 1e6 + 10;
int a[N] = {0}, b[N] = {0};
int n, m;
int l, r, c;

void insert(int l, int r, int c)
{
    b[l] += c;
    b[r + 1] -= c;
}

int main()
{
    scanf("%d%d", &n, &m);
    // 获取a数组
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    // 构造其差分数组
    for (int i = 1; i <= n; ++i) insert(i, i, a[i]);
    
    while (m--)
    {
        scanf("%d%d%d", &l, &r, &c);
        insert(l, r, c);
    }
    
    // 推导a数组
    for (int i = 1; i <= n; ++i) a[i] = (b[i] += b[i - 1]);
    // 打印最终数组
    for (int i = 1; i <= n; ++i) printf("%d ", a[i]);
    return 0;
}

其实可以不用创建 a n a_n an数组,直接使用 S n S_n Sn数组即可

#include <iostream>
using namespace std;

const int N = 1010;
int S[N][N] = {0};
int n, m, q;
int x1, y1, x2, y2;

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    // 获取原矩阵
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%d", &S[i][j]);
    // 构建前缀和矩阵
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            S[i][j] += (S[i - 1][j] + S[i][j - 1] -S[i - 1][j - 1]);
            
    // 处理询问
    while (q--)
    {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        printf("%d\n", S[x2][y2] - S[x2][y1 - 1] - S[x1 - 1][y2] + S[x1 - 1][y1 - 1]);
    }
    return 0;
}

798. 差分矩阵

798. 差分矩阵 - AcWing题库
image.png

#include <iostream>
using namespace std;

const int N = 1010;
int n,m,q;
int x1, y1, x2, y2, c;
int a[N][N] = {0}, b[N][N] = {0};

void insert(int x1, int y1, int x2, int y2, int c)
{
	b[x1][y1] += c;
	b[x2 + 1][y1] -= c;
	b[x1][y2 + 1] -= c;
	b[x2 + 1][y2 + 1] += c;
}

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    
    // 获取a矩阵
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%d", &a[i][j]);
    
    // 构建其差分矩阵
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            insert(i, j, i, j, a[i][j]);
    
    // 根据请求修改差分矩阵 
    while (q--)
    {
        scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
        insert(x1, y1, x2, y2, c);
    }
    
    // 根据差分矩阵与前缀和公式推导原矩阵
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            b[i][j] += (b[i -1][j] + b[i][j - 1] - b[i - 1][j - 1]);
            
    // 输出原矩阵
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)
            printf("%d ", b[i][j]);
        printf("\n");
    }
    
    return 0;
}

这里最好将差分数组以及原数组的i = 0以及j = 0的位置初始化为0并且不使用,从下标为1的位置开始使用数组。因为最后推导原数组中,需要用到这些下标为0的元素

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Unity Shader】从入门到感慨(2)用C#画一个立方体

文章目录 一、构成一个立方需要多少个顶点?二、定义三角面的索引数组:三、定义UV坐标数组:四、最后构建Mesh:五、完整代码:一、构成一个立方需要多少个顶点? 这个问题是面试经常被问到的题。如上图,我们知道在几何中立方体有6个面,8个顶点。但在图形学中,顶点指的是模…

翻过那座山——Gitlab流水线任务疑难之编译有子模块的项目指南

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不是…

QT入门基础知识

什么是QT QT是一个跨平台的C图像用户界面应用程序框架QT在1991年由奇趣科技开发QT的优点 跨平台,几乎支持所有平台接口简单&#xff0c;容易上手一定程度上简化了内存回收机制有很好的社区氛围可以进行嵌入式开发 QWidget QT注意事项 命名规范 类名 首字母大写&#xff0c;单…

golang vscode环境报错gopls was not able to find modules in your workspace的解决方式

目录 错误提示 分析 解决方式 方法一&#xff1a;将workspace与项目路径保持一致 方案二&#xff1a;使用go work指明纳入工作区的的module 总结 错误提示 golang从老版本升级到go1.20.5后打开vscode&#xff0c;发现代码不能自动补全了&#xff0c;而且vscode跳出一下的…

微服务基础介绍

Part1一、基本概念 微服务最主要的功能是根据业务拆分成一个一个的子服务&#xff0c;实现功能的去耦合&#xff0c;每一个微服务提供单个业务功能的服务&#xff0c;各司其职&#xff0c;从技术角度看就是一种灵活独立的单元&#xff0c;能够自行单独启动和关闭&#xff0c;一…

Docker学习笔记1

PaaS&#xff1a; 一、虚拟化分类&#xff1a; 虚拟化资源提供者&#xff1a; 1&#xff09;硬件平台虚拟化 2&#xff09;操作系统虚拟化 虚拟化实现方式&#xff1a; type I: 半虚拟化 type II&#xff1a;硬件辅助全虚拟化 type III&#xff1a; 软件全虚拟化&#xff1a; …

【C++】模版进阶

目录 一、非类型模版参数二、模板的特化1、概念2、函数模版特化3、类模板特化1.全特化2.偏特化3.类模板特化应用示例 三、模版分离编译1、什么是分离编译2、模板的分离编译3、模板的优缺点 一、非类型模版参数 模版参数分为类型模版参数与非类型模版参数 类型模版参数&#x…

[进阶]网络通信:UDP通信,一发一收、多发多收

UDP通信 特点&#xff1a;无连接、不可靠通信。不事先建立连接&#xff1b;发送端每次把要发送的数据&#xff08;限制在64KB内&#xff09;、接收端1P、等信息封装成一个数据包&#xff0c;发出去就不管了。Java提供了一个java.net.Datagramsocket类来实现UDP通信。 Datagram…

Springboot项目使用原生Websocket

目录 1.启用Websocket功能2.封装操作websocket session的工具3.保存websocket session的接口4.保存websocket session的类5.定义websocket 端点6.创建定时任务 ping websocket 客户端 1.启用Websocket功能 package com.xxx.robot.config;import org.springframework.context.a…

NSSCTF MOBILE [SWPU 2019]easyapp 详细题解

文章目录 一. 前言二. 安装安卓SDK三. 安装安卓模拟器(推荐夜神模拟器)四. 安装frida和objection五. 解题过程六. 总结 一. 前言 题目地址:[SWPU 2019]easyapp大佬题解[SWPU 2019]easyapp pwjcw的WriteUp 大佬的题解很简单,直接hook就可以看到返回值,但是我看了半天没看明白是…

Redis简介

Redis是基于内存&#xff0c;也可以基于磁盘持久化nosql数据库&#xff0c;使用c语言开发。 数据存储结构&#xff1a;key-value 安装环境准备 Redis使用c语言开发&#xff0c;需要使用gcc编译程序进行编译。 1&#xff09; 安装gcc a) 从磁盘镜像中进行安装&#xff1a;&…

决策树分类算法

#CSDN AI写作助手创作测评 目录 ID3算法 1.算法原理 2.代码实现 3.ID3算法的优缺点分析 C4.5算法 1.原理 2.优缺点 心得感受 决策树表示方法是应用最广泛的逻辑方法之一&#xff0c;它从一组无次序、无规则的事例中推理出决策树表示形式的分类规则。在决策树的内部…

Java集合详解

集合详解 1、集合&#xff0c;也可以说是容器。由两大接口派生而来&#xff0c;一个是collection&#xff0c;主要用于存储单一元素&#xff1b;另一个是map接口&#xff0c;主要用于存储键值对。 Collection接口 Map接口 2、集合和数组 在之前我们保存多个数据可以使用数组…

Tcl常用命令备忘录-正则命令篇

正则表达式是一种用于匹配、查找、替换文本中特定模式的工具。在Tcl脚本中&#xff0c;可以使用正则表达式对字符串进行匹配、查找和替换。 regexp 语法&#xff1a; regexp ?选项? 正则表达式 字符串 ?变量1 变量2 ...? 其中&#xff0c;?选项?为可选项&#xff0c;…

Spring Security OAuth2授权原理、流程与源码解读

文章目录 前言AuthorizationServerConfigurerAdapter(身份认证服务配置适配器)OAuth2AuthorizationServerConfiguration(OAuth2授权服务配置) EnableAuthorizationServer(开启身份认证服务)AuthorizationServerEndpointsConfigurations身份认证服务站点配置类AuthorizationEndp…

Qt编写精美输入法(历时十年迭代/可换肤/支持Qt4/5/6/win/linux/mac/嵌入式等)

一、前言 大概是从2012年就开始研究用Qt写输入法&#xff0c;因为项目需要&#xff0c;嵌入式板子上&#xff0c;没有对应的输入法&#xff0c;当初使用过很多NVR&#xff0c;里面也是鼠标按下弹出输入法面板进行输入&#xff0c;可以切换数字和字母及中文&#xff0c;于是借鉴…

jmeter如何进行http压力测试

目录 前言&#xff1a; 1、添加线程组&#xff1a; 2、添加采样器&#xff1a; 3、添加监视器 压力测试知识说明 前言&#xff1a; JMeter是一个基于Java的开源压力测试工具&#xff0c;可用于评估Web应用程序的性能&#xff0c;包括HTTP、HTTPS、FTP、SOAP、Restful、JD…

Oracle-高版本SQL优化分析(bind mismatch)

背景: 接到用户报障说一套Oracle19c数据库近期出现insert语句执行变慢的情况&#xff0c;执行一次数据插入需要1秒的时间&#xff0c;而且问题发生的数据库是跑在一体机上面&#xff0c;数据插入正常不应该这么慢&#xff0c;需要分析插入慢的原因 问题: 数据库近期出现insert…

StarRocks 文章收集

StarRocks在58的实践 StarRocks在58的实践 - 墨天轮StarRocks在58的实践 --2022-06-08https://www.modb.pro/db/639611 StarRocks之系统架构 StarRocks之系统架构 - 墨天轮https://www.modb.pro/db/610300 StarRocks小规模集群部署最佳实践(1/2) 0016.S StarRocks小规模集…

2自由度并联仿生腿的制作

1. 运动功能说明 本文实例将实现2自由度并联仿生腿模组运动起来&#xff0c;模拟实现狗腿行走的动作。 2. 结构说明 2自由度并联仿生腿模组是由两个舵机驱动的&#xff0c;它的所有动作都将在两个舵机的配合运动下实现。 3. 运动原理说明 2自由度并联仿生腿模组运动的点位如下…