c++算法笔记

算法归纳

前言:数组知识

c语言,c++语言的数组地址是连续的,而java语言当中不对程序员暴露其元素的地址,寻址操作完全交给虚拟机。

(一)二分查找

写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
第一种写法:[left, right]
注意点:
①while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=;
②if (nums[middle] > target) right 要赋值为 middle - 1;(因为nums[middle]不等于target,而我们是右闭区间,包括了right)
在这里插入图片描述
代码如下:

// 版本一
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

第二种写法:[left, right)
注意点:
①while (left <right) 要使用 < ,因为left == right是没有意义的;
②if (nums[middle] > target) right 要赋值为 middle ;(而我们是右开区间,不包括right)
在这里插入图片描述
代码如下:

// 版本二
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

(二)双指针

用途

双指针算法一般是采用左右指针,对数组、字符串进行查找或排序

1.对撞指针

一个指针指向最左端,一个指针指向最右端,向中间逼近

eg:翻转数组,翻转字符串

2.快慢指针

一个指针走得快,一个指针走得慢

eg:1. 判断单链表是否存在环

​ 2. 寻找循环链表的入口

​ 3. 寻找链表的中间节点(快指针一次走两节点,慢指针一次走一个节点,当快指针指向最后一个节点时,慢指针刚好指向中间节点)

​ 4. 判断两个链表是否相交

3.滑动窗口

(三)前缀和

前缀数组定义

前缀数组a[n];

数组b[n];

a[n]实际上就是对应的b数组的前n项和;

eg:

a[5]=b[1]+b[2]+b[3]+b[4]+b[5];

作用

在蓝桥杯每日一题中的3956截断数组中有用到

(四)差分

差分数组定义

差分数组b[n];

数组a[n];

b[n]实际上就是每一项数值都等于对应a[n]-a[n-1];恰好是和前缀和相反的

作用

当我们需要改变a数组中的某一段区域的值(让a[m]到a[n]中的每一项加c)时:

1.可以借助差分数组b,让b[m]+c,此时会导致如果利用差分数组求前项和得到的a数组中自m项起都会在原来的基础上加一个c;

2.但是此时的a[n]之后的项也加c了,所以我们可以让b[n+1]减去一个c,此时借助b数组前缀和求得的新a数组就满足要求了

在蓝桥杯每日一题中的3729改变数组元素中用到过

(五)字符哈希

在这里插入图片描述

最后得到的子串哈希值是:((hash[q]-hash[p-1]*p[q-p+1])%MOD+MOD)%MOD

(六)哈希表(主要针对C++中的unordered_map和unordered_set的常用操作)

哈希表讲解和构造

见bilibili链接
b站哈希表讲解视频

大概就是把需要储存查找的数据,找到其中的关键值,通过哈希函数求k值,储存在哈希表结构内,然后方便我们进行查找

求k值常用方法:除留余数法

处理冲突方法(个人觉得也就是储存结构):

开放定址法,链地址法

开放地址法

储存的时候,如果发现当前key计算之后的地址与之前的数据地址有冲突,直接去寻找空着的地址(一直向后寻找,或者+1,-1,+4,-4…),存入数据;那么当寻找的时候,就可能遇到去key本来计算出来的地址位置时,找不到对应的数据,这个时候就可以使用探测法,具体探测方法根据储存时的方法有关。

链地址法

储存的时候,构建一个类似于邻接表的结构,一个数组后链接很多个链表,当我们计算key值的地址出现冲突时,就将他们都链接到对应地址后的链表上,方便于寻找

unordered_map常用操作(还是不太会用)

建立

unordered_map <int,int>哈希表名字

向哈希表中添加元素
insert 函数
m.insert(pair<int,int>(1, 10));
m.insert(pair<int,int>(2, 20));
用数组方法直接添加
m[3]=30;
m[4]=40;
成员函数
begin(),end()函数
m.begin() //指向哈希表的第一个容器
m.end()  //指向哈希表的最后一个容器,实则超出了哈希表的范围,为空
find()查找函数
m.find(2)  //查找key为2的键值对是否存在 ,若没找到则返回m.end()
if(m.find(2)!=m.end()) //判断找到了key为2的键值对
count() 查找函数

查找哈希表中key为3的键值对,返回其数量,为1,则找到,若没找到则返回0

m.count(3)  //返回 1
m.count(5)   //返回0
size()函数
m.size()   //返回哈希表的大小
empty()函数
m.empty()  //判断哈希表是否为空,返回值为true/false
clear()函数
m.clear()  //清空哈希表
swap()函数

交换两个哈希表中的元素,整个哈希表的键值对全部都交换过去

unordered_map<int,int> m1;
unordered_map<int,int> m2;
m1.swap(m2);
swap(m1,m2);

**unordered_set常用操作(更好用)

unordered_set<string> first//容器定义
first.empty()//判断容器是否是空,是空返回true,反之为false
first.size()//返回容器大小
first.maxsize()//返回容器最大尺寸
first.begin()//返回迭代器开始
first.end()//返回迭代器结束
first.find(value)//返回value在迭代器的位置
first.count(key)//返回key在容器的个数
first.insert(value)//将value插入到容器中
first.erase(key)//通过key删除
first.clear()//清空容器

count比较适合来判断容器中是否有这个元素(根据返回值是否为0判断)

(七)递推

具体CSDN讲解:

CSDN

打开链接方法:ctrl+点击

1.汉诺塔

移动规则:

将A塔座上的n个盘子挪动到C塔座上

每次只能移动一个圆盘;圆盘可以插在X、 Y和Z中的任何一个塔座上;任何时刻都不能将一个较大的圆盘压在较小的圆盘之上

设f(n)为有n个盘子时需要挪动的次数。

f(0)=0;

f(1)=1;(限制条件)

f(n)=f(n-1)+1+f(n-1)=2*f(n-1)+1;

解释(f(n)公式的由来)

第一个f(n-1)表示将A塔座上的n-1个盘子挪到B塔座上(这里的次数是和f(n-1)相等的,因为f(n-1)就代表将n-1个盘子从A塔座上挪到C塔座上,是同理的);

中间的1表示将A塔座上剩余的最后一个盘子直接挪到C塔座上

最后一个f(n-1)表示将B塔座上的n-1个盘子挪到C塔座上(这里的次数同样等于f(n-1));

2.求斐波那契数(较简单)

3.猴子吃桃(较简单,逆推法)

4.数字三角形(顺推法)

请编一个程序计算从顶到底的某处的一条路径,使该路径所经过的数字总和最大。只要求输出总和

img

a【n】【m】存放数据(如图右侧),除去存放数据位置以外其余位置均为0(方便后续正确计算)

设f【n】【m】表示当前位置的最大路径和;

f【1】【1】=a【1】【1】(存放数据时每一层都从下标1开始存放)(限制条件)

f【n】【m】=max{f【n-1】【m-1】,f【n-1】【m】};(实际上就是对应左图除去第一层外的每一个元素,都将自己和头顶上的两个数字中较大的那一个加上,一直这样连续地求下去,就能得到每一个位置的最大路径和了)

最后在得到的最后一层f中循环遍历,找到最大的路径和即可。

5.骨牌排满方格

有 2n 的一个长方形方格,用一个12 的骨牌铺满方格。

编写一个程序,试对给出的任意一个n(n>0), 输出铺法总数。

img

算法分析:

1.当n=1时:只有一种情况

img

2.当n=2时,要不横向排列,要不纵向排列,两种情况,如上图左侧

3.当n=3时,如上图右侧

4.当n=4时,如下图:

img

总结:除了n=1,n=2以外,可以进行讨论,如果第一个骨牌纵向分布,那么还剩下n-1个骨牌位置需要确定(如上图前三个),即f(n-1);

如果第一个骨牌横向分布,那么第二个骨牌的位置也就确定了,那么还剩下n-2个骨牌位置需要确定(如上图后两个),即f(n-2);

因此有:

f(1)=1;

f(2)=2;(限制条件)

f(n)=f(n-1)+f(n-2);

6.吃糖果

名名的妈妈从外地出差回来,带了一盒好吃又精美的巧克力给名名(盒内共有 N 块巧克力,20 > N >0)。

妈妈告诉名名每天可以吃一块或者两块巧克力。假设名名每天都吃巧克力,问名名共有多少种不同的吃完巧克力的方案。

算法分析:同5.骨牌排满方格

(八)kmp算法

主要针对前缀循环元的问题—见蓝桥杯每日一题Week2—141.周期。

题目描述:

一个字符串的前缀是从第一个字符开始的连续若干个字符,例如 abaab 共有 55 个前缀,分别是 aababaabaaabaab

我们希望知道一个 N 位字符串 S的前缀是否具有循环节。

换言之,对于每一个从头开始的长度为 i(i>1)的前缀,是否由重复出现的子串 A组成,即 AAA…A (A 重复出现 K次,K>1)。

如果存在,请找出最短的循环节对应的 K 值(也就是这个前缀串的所有可能重复节中,最大的 K 值)。

算法分析:

总结:

一个字符串的next数组,如果当前字符对应的 i%(i-next【i】)==0,那么当前的字符以前的前缀字符串具有循环元,**i/(i-next【i】)**就是它的循环元个数

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

(九)通过中序遍历和后序遍历重建二叉树,二叉树的层序遍历(直接给根节点的情况)

见蓝桥杯每日一题:1497. 树的遍历 - AcWing题库

代码:
#include<stdio.h>
#include<malloc.h>
typedef struct Bitree
{
    int data;
    struct Bitree* lchild;
    struct Bitree* rchild;
}*pBitree,bitree;
typedef struct queue
{
    int data;
    pBitree p;
}queue;
void buildtree(int* a,int* b,int n,pBitree* t);
void cengtraverse(pBitree root,int n);
int main()
{
    int n;
    scanf("%d",&n);
    int a[n];//后序遍历数组
    int b[n];//中序遍历数组
    int i;
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(i=0;i<n;i++)
    {
        scanf("%d",&b[i]);
    }
    pBitree root;
    buildtree(a,b,n,&root);//根据中序遍历和后序遍历重建二叉树
    cengtraverse(root,n);//层序遍历二叉树
    return 0;
}
void buildtree(int* a,int* b,int n,pBitree* t)
{
    int i=0;
    //找到中序遍历中根节点的位置,确定左右子树的节点个数
    for(i=0;i<n;i++)
    {
        if(a[n-1]==b[i])
        {
            break;
        }
    }
    //如果没有找到就return
    if(i>=n)
    {
        return;
    }
    //创建根节点
    *t=(pBitree)malloc(sizeof(bitree));
    (*t)->lchild=NULL;
    (*t)->rchild=NULL;
    (*t)->data=b[i];
    //创建左子树
    buildtree(a,b,i,&((*t)->lchild));//这里传入的n变成了i是因为左子树的节点个数只有i个(中序遍历中根节点左边的部分就是左子树的全部节点)
    //创建右子树
    buildtree(a+i,b+i+1,n-i-1,&((*t)->rchild));//这里传入的n变成n-i-1,是因为右子树节点的个数是n-i-1个(中序遍历中根节点右半部分就是右子树的全部节点),传入的后序遍历数组变成了原来后序遍历中右子树的数组部分,传入的中序遍历数组变成了原来中序遍历数组部分中右子树的部分。(关键点)
}
void cengtraverse(pBitree root,int n)
{
    int traverse[n];
    queue Q[n];
    int rear=0;
    int front=0;
    Q[rear].data=root->data;
    Q[rear++].p=root;
    int num=0;
    while(rear>front)
    {
        traverse[num++]=Q[front].data;
        //printf("%d\n",traverse[num-1]);
        if(Q[front].p->lchild!=NULL)
        {
            Q[rear].data=Q[front].p->lchild->data;
            Q[rear++].p=Q[front].p->lchild;
        }
        if(Q[front].p->rchild!=NULL)
        {
            Q[rear].data=Q[front].p->rchild->data;
            Q[rear++].p=Q[front].p->rchild;
        }
        front++;
    }
    int i;
    for(i=0;i<n;i++)
    {
        printf("%d ",traverse[i]);
    }
}
中序,后序建立二叉树思路:(递归)

根据中序加后序遍历重建二叉树
构造该二叉树的过程如下:

  1. 根据后序序列的最后一个元素建立根结点;
  2. 在中序序列中找到该元素,确定根结点的左右子树的中序序列;
  3. 在后序序列中确定左右子树的后序序列;
  4. 由左子树的后序序列和中序序列建立左子树;
  5. 由右子树的后序序列和中序序列建立右子树。

(十)最小生成树

1.普利姆算法

在这里插入图片描述

2.克鲁斯卡尔算法

在这里插入图片描述

(十一)C++相关知识回忆(2024蓝桥杯准备)

1.模板

#include<iostream>
using namespace std;
int main(){
    
}

2.输入输出

string a
cin>>a;//输入
cout<<a<<endl;//输出
getline(a);//接收字符串(可以有空格)(要用<string>库)

3.字符串

string s;//字符串
	cin>>s;//输入字符串(不保留空格)
	cout<<s<<endl;//输出字符串
//	string s2;
//	getline(cin,s2);//输入字符串(保留空格)(但是当前情况,前面已经有输入的情况,无法正常输入,因为残留了空格或者\n;
//	cout<<s2<<endl;
	string s3;//字符串
	cin>>s3;//输入字符串(不保留空格)
	cout<<s3<<endl;//输出字符串
	cout<<s3+s<<endl;//拼接字符串s和s3
	for(int i=0;i<s.size();i++){//循环输出字符串
		cout<<s[i]<<endl;
	}
//长度
	string a="cswedcfv";
	cout<<a.size();
//增加
	s.insert(1,"dewsf");//在字符串中插入(插入位置,“插入内容”)
	cout<<s<<endl;//输出字符串
//删除
	s.erase(6,2);//删除字符串中从第几个字符开始的几个字符
	cout<<s<<endl;//输出字符串
//修改
	s[1]='1';//修改字符串当中的字符
	cout<<s<<endl;//输出字符串
//查找
	s.find(args)  // 查找 s 中 args 第一次出现的位置
	s.rfind(args)  // 查找 s 中 args 最后一次出现的位置
    s.find_first_of(args)  // 在 s 中查找 args 中任何一个字符最早出现的位置
	s.find_last_of(args)  // 在 s 中查找 args 中任何一个字符最晚出现的位置
	例如:
	string s1 = "nice to meet you~"; 
	cout << s1.find_first_of("mey") << endl; // 输出结果为 3,'e' 出现的最早
	s.find_first_not_of(args)  // 查找 s 中 第一个不在 args 中的字符的位置
	s.find_last_not_of(args)  // 查找 s 中 最后一个不在 args 中的字符的位置
	例如:
	string s1 = "nice to meet you~";  
	cout << s1.find_first_not_of("nop") << endl; // 输出结果为 1 ,'i' 不在 "nop" 里	
//转化
	string s = to_string(val)//将数值转化为string
//反转
//需要<algorithm>库
    string s2 = "12345";    // 初始化一个字符串
    reverse(s2.begin(), s2.end()); // 反转 string 定义的字符串 s2 
    cout << s2 << endl; // 输出 54321

s.insert(1,“”);

s.erase(1,2);

s.find(“”);

s.rfind(“”);

s.find_fiirst_of(“”);

s=to_string(val);

4.algorithm库

(1).max()、min()、abs()函数

max():求两个数最大值
min():求两个数最小值
abs():求一个数的绝对值

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	int a = 3, b = 4;
	//求最大值
	int Max = max(a,b);
	//求最小值
	int Min = min(a,b);
	//求绝对值
	int Abs = abs(-3);
	cout << Max << Min << Abs;
	
	return 0;
 } 

(2)交换函数:swap()

用来交换x和y的值

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	int a = 3, b = 4;
	swap(a,b);
	cout << a << b;
	return 0;
 } 

(3)翻转函数:reverse()

翻转x-y区间的数组、容器的值。

1、翻转整个数组

翻转整个数组:

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	int a[5] = {11,22,33,44,55};
	reverse(a,a+5);
	for(int i = 0; i < 5; i++) 
		cout << a[i] << ' ';
	return 0;
 } 
2、对部分值的翻转,

翻转部分数组:

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	int a[5] = {11,22,33,44,55};
	reverse(a+3,a+5);
	for(int i = 0; i < 5; i++) 
		cout << a[i] << ' ';
	return 0;
 } 
3、翻转容器:

翻转整个容器:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main() {
	vector<int>v;
	//输入: 
	for(int i = 0; i < 5; i++) 
		v.push_back(i);
	//输出: 
	reverse(v.begin(), v.end());
	for(int i = 0; i < v.size(); i++) {
		cout << v[i] << ' ';
	}
	return 0;
 } 
(4)排序函数:sort()
1、对x-y区间的数组、容器进行排序。默认升序排列

数组升序排序:

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	int a[5] = {55,44,33,22,11};
	
	sort(a,a+5);
	
	for(int i = 0; i < 5; i++) 
		cout << a[i] << ' ';
		
	return 0;
 } 

2.数组降序排序,写一个简单的函数,改变排序功能:

数组降序排序:

#include<iostream>
#include<algorithm>
//意思是:若a>b,则a的优先级更大! 也就是说大的在前面。
bool cmp(int a, int b) {
	return a > b; 
}
using namespace std;
int main() {
	int a[5] = {55,44,33,22,11};
	
	sort(a,a+5,cmp);			//这里需要加上自己自定义的函数
	
	for(int i = 0; i < 5; i++) 
		cout << a[i] << ' ';
	return 0;
 } 
3、同理,如果想对结构体排序,也需要自定义优先级。像这样:

结构体排序:

#include<iostream>
#include<algorithm>
using namespace std;
//用sort函数对结构体排序 
struct Student {
	int high;
	int weigh;
}student[10];
//a.high如果小于b.high,则a结构体的优先级更大, 也就是说:high小的结构体排在前面。 
bool cmp(Student a, Student b) {
	return a.high < b.high;
} 
int main() {
	for(int i = 0; i < 10; i++) {
		student[i].high = i ;
	}
	sort(student, student+10, cmp);		//将自定义的函数添加上。
	for(int i = 0; i < 10; i++) {
	cout << student[i].high << ' ';
}
return 0;
}
4、对容器排序:

容器升序排序:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main() {
	vector<int>v;
	vector<int>::iterator it;
	//输入: 
	for(int i = 5; i > 0; i--) 
		v.push_back(i); 
	//输出: 
	it = v.begin(); 
	sort(it, it+3);
//	sort(v.begin(), v.end())
	for(int i = 0; i < v.size(); i++) {
		cout << v[i] << ' ';
	}
	return 0;
 } 

(5)查找函数:find()

查找某数组指定区间x-y内是否有x,若有,则返回该位置的地址,若没有,则返回该数组第n+1个值的地址。(好烦有木有,为啥要返回地址。还要转化o(╥﹏╥)o)
1、数组中查找是否有某值:一定一定一定要满足代码中这两个条件。
第一个条件是:p-a != 数组的长度。p是查找数值的地址,a是a[0]的地址。
第二个条件是:*p == x; 也就是该地址指向的值等于我们要查找的值。
最后输出p-a+1; p-a相当于x所在位置的地址-a[0]所在位置的地址, 但因为是从0开始算, 所以最后需要+1。

对数组查找:
#include<iostream>
#include<algorithm>
using namespace std;
int main() {  
	int a[5] = {11,22,33,44,55}	
	int *p = find(a,a+5,33);				//定义指针,指向查找完成后返回的地址,5为a2数组长度 
	if(((p-a) != 5) && (*p == x))		//若同时满足这两个条件,则查找成功,输出 
	cout << (p-a+1);					//输出所在位置 
	return 0;
}
(6)查找某值出现的次数:count()
在数组中查找x 在某区间出现的次数:

代码:

#include<iostream>
#include<algorithm>
using namespace std;
int main() {  
	int a[5] = {11,22,33,44,44};
	cout << count(a, a+5, 44);	
	return 0;
 } 
(7)求最大公因数:__gcd()

震惊把!在我最开始知道竟然有这个函数时,我也是震惊的!
另外,用二者乘积除以最大公因数即可得到最小公倍数。 因此没有求最小公倍数的函数。

代码:

#include<iostream>
#include<algorithm>
using namespace std;
int main() {  
	int a = 12, b = 4;
	int Gcd = __gcd(a,b);
	cout << Gcd;
	return 0;
 } 

6.容器长度

//字符串string
string a="cswedcfv";
cout<<a.size();
//字符串数组char a1[]
//对于字符串数组,使用strlen()函数来获取字符串数组的长度。
char a1[] = "fwegweasdasdwqew";
cout << strlen(a1) << endl;
//数字数组int a[]
int arr[] = { 1,5,9,10,9,2 };
int n=sizeof(arr) / sizeof(arr[0]);

7.cmath库

(1)绝对值函数

浮点数:

fabs(double x);

整型:

abs(x);

效果与上方if同等。

(2)幂计算:

开方
√a

sqrt(double x);

乘方

pow(a,b);

表示b个a相乘。

(3)三角函数:
hypot(double x,double y);

x、y为直角三角形两条直角边,它可以求出第三条边。

应用

#include<iostream>
#include<cmath>
using namespace std;
int main(){
    int x,y;
    cin>>x>>y;
    cout<<hypot(x,y);
    return 0;
} 
(4)取整:
double ceil(double x);//取上整,返回比x大的最小整数

double floor(double x);//取下整,返回比x小的最大整数,即高斯函数[x]

double round(double x); //返回x的四舍五入值
(5)实践
#include<iostream>
#include<cmath>
//1.绝对值
//2.乘方
//3.取整
using namespace std;
int main(){
	float a=-5.63;
	cout<<fabs(a);//1.绝对值
	cout<<"\n";
	float b=2.44;
	cout<<sqrt(b);//2.乘方
	cout<<"\n";
	cout<<pow(a,2);
	cout<<"\n";
	cout<<ceil(a);//3.取整
	cout<<"\n";
	cout<<floor(a);
	cout<<"\n";
	cout<<round(a);
	return 0;
}

运行结果:

5.63
1.56205
31.6969
-5
-6
-6

8.栈和队列

使用标准库的栈和队列时,先包含相关的头文件

#include

#include

定义栈如下:

stack stk;

定义队列如下:

queue q;

栈提供了如下的操作

s.empty()               //如果栈为空返回true,否则返回false
s.size()                //返回栈中元素的个数
s.pop()                 //删除栈顶元素但不返回其值
s.top()                 //返回栈顶的元素,但不删除该元素
s.push()                //在栈顶压入新元素

队列提供了下面的操作

q.empty()               //如果队列为空返回true,否则返回false
q.size()                //返回队列中元素的个数
q.pop()                 //删除队列首元素但不返回其值
q.front()               //返回队首元素的值,但不删除该元素
q.push()                //在队尾压入新元素
q.back()                //返回队列尾元素的值,但不删除该元素

——————————————————————————————————
持续更新中(2024.7.13)

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值