PAT第九章专题复习

PAT第九章专题复习

  • 二叉树遍历与树的遍历

    • 二叉树中序+层序/先序/后序建立树,输出中序/先序/后序/ 层序序列。(背模板即可)

      • 层序+中序确定树模板还需要反复加强理解
    • 不建树做法:当结点数比较大并且比较容易操作时

      • 给出中序序列和先序序列,再给出两个点,求这两个点的最近公共祖先【PAT A 1151】

        • 思路:

          ①不用建树,则需要中序序列的inl和inr下标以及先序序列的根节点下标preRoot。

          ②求最近公共祖先,函数参数还需要传入的两个数的值。

          ③在递归函数中,第一步是递归边界;第二步是确定中序序列根节点下标以及a和b两个数在中序序列中的下标位置。第二步自然而然想到用map来做会方便许多。

          ④第三步递归式。总共有5种情况,都在左子树、都在右子树、分别在左右子树、aIn等于中序根节点、bIn等于中序根节点

        • ·代码实现

          #include<bits/stdc++.h>
          using namespace std;
          map<int, int> pos;
          vector<int> pre, in; 
          //不用建树确定,则需要中序序列以及先序的根节点位置 
          void lca(int inl, int inr, int preRoot, int a, int b){
          	//递归边界
          	if(inl > inr)return;
          	//递归式
          	//1、计算根节点在中序序列中下标位置以及a、b节点在中序序列中下标位置
          	int inRoot = pos[pre[preRoot]], aIn = pos[a], bIn = pos[b];
          	//2、判断各种情况
          	//2.1 aIn和bIn都在左子树,往左子树递归
          	if(aIn < inRoot && bIn < inRoot)lca(inl, inRoot-1, preRoot + 1, a, b);
          	//2.2 aIn和bIn分别在左右子树两侧,找到公共祖先 
          	else if((aIn < inRoot && bIn > inRoot) || (aIn > inRoot && bIn < inRoot)){
          		printf("LCA of %d and %d is %d.\n", a, b, in[inRoot]);
          	} 
          	//2.3 aIn和bIn都在右子树,往右子树递归
          	else if(aIn > inRoot && bIn > inRoot)lca(inRoot + 1, inr, preRoot + (inRoot - inl) + 1, a, b);
          	//2.4 aIn等于inRoot
          	else if(aIn == inRoot){
          		printf("%d is an ancestor of %d.\n", a, b);
          	
          	}
          	//2.5 bIn等于inRoot 
          	else if(bIn == inRoot){
          		printf("%d is an ancestor of %d.\n", b, a);
          	}
          }
          int main(){
          	int m, n, a, b;
          	cin >> m >> n;
          	in.resize(n + 1), pre.resize(n + 1);
          	for(int i = 1; i <= n; i++){
          		cin >> in[i];
          		//利用map,直接将值与下标对应
          		pos[in[i]] = i; 
          	} 
          	for(int i = 1; i <= n; i++)cin >> pre[i];
          	for(int i = 0; i < m; i++){
          		cin >> a >> b;
          		//判断是否出现在树中
          		if(pos[a] == 0 && pos[b] == 0){
          			printf("ERROR: %d and %d are not found.\n", a, b);
          		} else if(pos[a] == 0 || pos[b] == 0){
          			printf("ERROR: %d is not found.\n", pos[a] == 0 ? a : b);
          		}else{
          			lca(1, n, 1, a, b);
          		}
          	}
          	return 0;
          } 
          
      • 最近公共祖先+完全二叉搜索树【PAT A 1143】

        • 思路:

          ①和上一题相比,完全二叉搜索树的结点值本身是有序的,就没有必要和上一题一样取出结点下标来进行比较,而直接可以拿值进行比较。因为是完全二叉搜索树,可以夹出唯一一个结点值,是它在u和v的中间或者等于u和v两者中的一个。

        • 代码实现

          #include<bits/stdc++.h>
          using namespace std;
          map<int, int> mp;
          int main(){
          	int m, n, u, v, temp;
          	cin >> m >> n;
          	vector<int> pre(n);
          	for(int i = 0; i < n; i++){
          		cin >> pre[i];
          		mp[pre[i]] = 1;
          	} 
          	//直接进行多种情况判断
          	for(int i = 0; i < m; i++){
          		cin >> u >> v;
          		//对pre数组遍历 
          		for(int j = 0; j < n; j++){
          			temp = pre[j];
          			//利用循环+break模拟递归 
          			if((temp > u && temp < v) || (temp < u && temp > v) || (temp == u) || (temp == v))break;
          		}
          		if(mp[u] == 0 && mp[v] == 0){
          			printf("ERROR: %d and %d are not found.\n", u, v);
          		}else if(mp[u] == 0 || mp[v] == 0){
          			 printf("ERROR: %d is not found.\n", mp[u] == false ? u : v);
          		}else if(temp == u || temp == v){
          			printf("%d is an ancestor of %d.\n", temp, temp == u ? v : u);
          		}else{
          			printf("LCA of %d and %d is %d.\n", u, v, temp);
          		}
          	} 
          	return 0;
          } 
          
      • 给出先序序列和中序序列,求后序序列第一个值。结点个数最多有50000个。【PAT A 1138】

        • 思路:

          ①结点个数很大,不能建树做,明显会超时。

          ②使用不建树的思想,dfs函数中参数需要中序序列的inl和inr两个端点,以及先序序列确定的根节点下标preRoot。

          ③dfs函数内部,首先是递归边界;第二步是递归式,递归式参照后序遍历的模板,即先遍历左子树再遍历右子树,最后打印根节点的形式。

        • 代码实现

          #include<bits/stdc++.h>
          using namespace std; 
          int n, flag = 0;
          vector<int> pre, in;
          unordered_map<int, int> pos;//记录中序序列中值的下标 
          void dfs(int inl, int inr, int preRoot){
          	//递归边界
          	if(flag || inl > inr)return;
          	//递归式
          	//1、计算中序序列中根节点位置
          	int inRoot = pos[pre[preRoot]];
          	//2、输出后序序列的形式:先打遍历左子树然后再遍历右子树最后打印根节点 
          	dfs(inl, inRoot - 1, preRoot + 1);
          	dfs(inRoot + 1, inr, preRoot + 1 + inRoot - inl); 
          	if(!flag){
          		printf("%d", in[inRoot]);
          		flag = 1;
          	} 
          }
          int main(){
          	cin >> n;
          	pre.resize(n + 1), in.resize(n + 1);
          	for(int i = 1; i <= n; i++){
          		cin >> pre[i];
          	}
          	for(int i = 1; i <= n; i++){
          		cin >> in[i];
          		pos[in[i]] = i;
          	}
          	dfs(1, n, 1);
          	return 0;
          }
          
      • 给出先序序列和后序序列,输出中序序列;判断中序序列是否唯一即树是否唯一【PAT A 1119】

        • 思路:

          ①dfs函数参数有先序的两个端点prel和prer,以及后序的两个端点postl和postr。

          ②dfs函数中,首先确定递归边界——当prel和prer相等时,可以夹出唯一的值即树的最左边结点值,压入到in容器中。 第二部分递归式,首先寻找post中下一个根节点在pre中的位置下标;如果pre部分没有左子树部分,那么就说明树不是唯一的(可以画图看),如果存在,则往左子树部分递归;第三步将根节点压入到in容器中,此处根节点为postr所在下标的数;第四步往右子树进行递归。

        • 代码实现

          #include<bits/stdc++.h>
          using namespace std;
          vector<int> pre, post, in;
          int uniq = 0;
          void dfs(int prel, int prer, int postl, int postr){
          	//递归边界
          	if(prel == prer){//夹出一个数,也就是树最左边的结点 
          		in.push_back(pre[prel]);
          		return;
          	} 
          	//递归式
          	if(pre[prel] == post[postr]){
          		//在先序序列中寻找下一个根节点位置
          		int i = prel + 1;
          		while(i <= prer && pre[i] != post[postr-1])i++;
          		if(i - prel > 1){//说明存在左子树部分 
          			dfs(prel + 1, i-1, postl, postl + i-prel-1-1);
          		}else{
          			uniq = 1;//说明该树不唯一 
          		} 
          		//中序根节点入in容器中
          		in.push_back(post[postr]);
          		//往右子树遍历
          		dfs(i, prer, postl + i-prel-1, postr-1); 
          		
          	} 
          }
          int main(){
          	int n;
          	cin >> n;
          	pre.resize(n), post.resize(n);
          	for(int i = 0; i < n; i++)cin >> pre[i];
          	for(int i = 0; i < n; i++)cin >> post[i];
          	dfs(0, n-1, 0, n-1);
          	if(uniq)printf("No\n");
          	else printf("Yes\n");
          	for(int i = 0; i < in.size(); i++){
          		printf("%d", in[i]);
          		if(i != in.size() - 1)printf(" ");
          		else printf("\n"); 
          	}
          	return 0;
          }
          
      • 给出中序序列和后序序列,求层序序列【PAT A 1020】

        • 思路:

          ①层序序列想到给树的结点从小到大进行编号;编号可以按先序遍历的形式,当遍历到根节点的时候,给树编号;编号用map来存储,那么map会自动根据第一个键值升序排序,也就是层序输出的顺序。

        • 代码实现

          #include<bits/stdc++.h>
          using namespace std;
          vector<int> post, in;
          unordered_map<int, int> pos;
          map<int, int> level;//map会根据第一个值升序排序 
          void dfs(int inl, int inr, int postRoot, int index){
          	//递归边界
          	if(inl > inr)return;
          	//计算根节点在中序序列中下标
          	int inRoot = pos[post[postRoot]];
          	//递归式
          	//先序模板,将根节点与结点下标重新编号对应
          	level[index] = in[inRoot];
          	//左递归
          	dfs(inl, inRoot - 1, postRoot - 1 + inRoot - inr, 2 * index);
          	//右递归
          	dfs(inRoot + 1, inr, postRoot - 1, 2 * index + 1); 
          }
          int main(){
          	int n;
          	cin >> n;
          	post.resize(n + 1), in.resize(n + 1);
          	for(int i = 1; i <= n; i++)cin >> post[i];
          	for(int i = 1; i <= n; i++){
          		cin >> in[i];
          		pos[in[i]] = i;
          	}
          	dfs(1, n, n, 1);
          	auto it = level.begin();
          	printf("%d", it->second);
          	it++;
          	for(; it != level.end(); it++){
          		printf(" %d", it->second);
          	}
          	return 0;
          } 
          
    • 树遍历

      • 求树遍历权值最大路径【PAT A 1053]

        • 思路:

          ①本题思路不难,先建树,然后dfs遍历求权值最大的路径;接着对双重vector进行排序

          本题难点在双重vector的排序操作

          bool cmp(vector<int> a, vector<int> b){
              for(int i = 0; i < a.size() && i < b.size(); i++){
                  if(a[i] > b[i])return a > b;
              }
              if(a.size() > b.size())return a > b;
          }
          vector<vector<int> >path;
          vector<int> tempPath;
          path.push_back(tempPath);
          sort(path.begin(), path.end(), cmp);
          
        • 代码实现

          #include<bits/stdc++.h>
          using namespace std; 
          int n, m, s;
          struct node{
          	int v, w;
          	vector<int> child;
          }tree[110];
          vector<vector<int> >path;
          vector<int> tempPath;
          bool cmp(vector<int> a, vector<int> b){
          	for(int i = 0; i < a.size() && i < b.size(); i++){
          		if(a[i] > b[i])return a > b;
          	}
          	if(a.size() > b.size())return a > b;
          }
          void dfs(int root, int sum){
          	//递归边界
          	if(tree[root].child.size() == 0){
          		if(sum == s){
          			tempPath.push_back(tree[root].w);
          			path.push_back(tempPath);
          			tempPath.pop_back();
          		}
          		return;
          	} 
          	//递归式
          	tempPath.push_back(tree[root].w);
          	for(int i = 0; i < tree[root].child.size(); i++){
          		int value = tree[root].child[i];
          		dfs(value, sum + tree[value].w);
          	} 
          	tempPath.pop_back();
          }
          int main(){
          	int id, k, temp;
          	cin >> n >> m >> s;
          	for(int i = 0; i < n; i++){
          		cin >> tree[i].w;
          	} 
          	for(int i = 0; i < m; i++){
          		cin >> id >> k;
          		while(k--){
          			cin >> temp;
          			tree[id].child.push_back(temp);
          		}
          	}
          	//深度遍历
          	dfs(0, tree[0].w);
          	sort(path.begin(), path.end(), cmp);
          	for(int i = 0; i < path.size(); i++){
          		for(int j = 0; j < path[i].size(); j++){
          			printf("%d", path[i][j]);
          			if(j != path[i].size() - 1)printf(" ");
          			else printf("\n");
          		}
          	}
          	return 0;
          }
          
  • 二叉搜索树(二叉查找树)

    • 二叉搜索树+完全二叉树+层序遍历知识点结合【PAT A 1064】

      • 思路:

        ①二叉搜索树的性质是中序序列是有序的。将此题给出的序列升序排序之后,就是二叉搜索树的中序序列。

        ②同时,该树又是完全二叉树,完全二叉树的性质是下标之间有对应的关系。于是,问题转换为中序遍历完全二叉树,为树的结点赋值。

        ③层序遍历序列就是完全二叉树结点下标顺序排列,也就是按结点下标升序排序输出对应的结点值。

        本题很巧妙!!

      • 代码实现

        #include<bits/stdc++.h>
        using namespace std; 
        int n, num = 0;
        vector<int> in;
        struct node{
        	int data;
        }tree[1010];
        void inOrder(int index){
        	if(index > n)return;
        	//左递归
        	inOrder(index * 2);
        	//根节点赋值
        	tree[index].data = in[num++];
        	//右递归
        	inOrder(index * 2 + 1); 
        }
        int main(){
        	cin >> n;
        	in.resize(n);
        	for(int i = 0; i < n; i++){
        		cin >> in[i];
        	}
        	//升序排序 
        	sort(in.begin(), in.end());
        	inOrder(1);
        	//输出,按节点顺序输出即为层序遍历序列
        	for(int i = 1; i <= n; i++){
        		printf("%d", tree[i].data);
        		if(i != n)printf(" ");
        	} 
        	
        	return 0;
        } 
        
    • 中序遍历填充二叉搜索树+层序遍历输出结果【PAT A 1099】

      • 思路:

        ①将序列升序排序,为二叉搜索树中序序列。

        ②中序遍历二叉搜索树,填充值

        ③层序遍历输出序列

      • 代码实现

        #include<bits/stdc++.h>
        using namespace std; 
        int n, num = 0;
        vector<int> in;
        struct node{
        	int v, data;
        	int lchild, rchild;
        }tree[110];
        void inOrder(int root){
        	//递归边界
        	if(root == -1)return;
        	//左子树递归
        	inOrder(tree[root].lchild);
        	//根节点赋值
        	tree[root].data = in[num++];
        	//右子树递归
        	inOrder(tree[root].rchild); 
        }
        //层序遍历
        void layerOrder(int root){
        	queue<int> q;
        	q.push(root);
        	int cnt = 0;
        	while(!q.empty()){
        		int now = q.front();
        		q.pop();
        		printf("%d", tree[now].data);
        		cnt++;
        		if(cnt != n)printf(" ");
        		if(tree[now].lchild != -1)q.push(tree[now].lchild);
        		if(tree[now].rchild != -1)q.push(tree[now].rchild);
        	}
        }
        int main(){
        	cin >> n;
        	in.resize(n);
        	for(int i = 0; i < n; i++){
        		cin >> tree[i].lchild >> tree[i].rchild;
        		tree[i].v = i;
        	}
        	for(int i = 0; i < n; i++){
        		cin >> in[i];
        	}
        	sort(in.begin(), in.end());
        	//中序遍历填充二叉树
        	inOrder(0); 
        	//层序遍历输出结果
        	layerOrder(0); 
        	return 0;
        }   
        
    • 红黑树+二叉搜索树+ 先序序列【PAT A 1135】

      • 思路:

        ①红黑树不是AVL树,题目中给的是先序序列和二叉搜索树的性质来建树
        ②红黑树的条件:1、根结点时黑色的;2、结点不是红色就是黑色的;3、红色结点的孩子结点都是黑色的; 4、遍历每条路径黑色结点的个数都相同
        上述第3个条件,用递归判断,如果遇到红色结点的孩子不是黑色的,就返回false,最后返回左右两个结点的判断这种dfs方法十分值得学习!
        ④上述第4个条件,用递归判断,利用了AVL树当中的计算更新树高 + 计算树高的方法,不过是计算黑色结点的个数 ;是updateHeight方法 + getHeight方法的变形。

      • 代码实现

        #include<bits/stdc++.h>
        using namespace std;
        vector<int> v;
        struct node{
        	int val;
        	node *lchild, *rchild;
        };
        node* build(node *root, int val){
        	if(root == NULL){
        		root = new node();
        		root->val = val;
        		root->lchild = root->rchild = NULL;
        	}
        	//往左子树插入,不要忘记前面要等于root->lchild语句;如果没哟前面这句,
        	//将导致这个新建的结点没有连接在二叉树上。 
        	else if(abs(val) < abs(root->val)){
        		root->lchild = build(root->lchild, val);
        	}
        	//往右子树插入 
        	else root->rchild = build(root->rchild, val);
        	//建树完成返回结点
        	return root; 
        }
        //判断红色结点的左右孩子结点是否都是黑色的 
        bool judge1(node *root){
        	if(root == NULL)return true;
        	//左右孩子递归判断
        	if(root->val < 0){
        		if(root->lchild != NULL && root->lchild->val < 0)return false;
        		if(root->rchild != NULL && root->rchild->val < 0)return false;
        	} 
        	//最后返回两者的判断结果,取&&操作,只有两个都为真时才返回真 
        	//递归函数 
        	return judge1(root->lchild) && judge1(root->rchild);
        }
        //可以用求树高的函数模板来求解结点颜色的个数,
        //相当于将高度变为了黑色结点的个数 
        int getNum(node *root){
        	if(root == NULL)return 0;
        	int l = getNum(root->lchild);
        	int r = getNum(root->rchild);
        	return root->val > 0 ? max(l, r) + 1 : max(l, r);
        } 
        //判断任意遍历路径中的黑色结点个数是否相同 
        bool judge2(node *root){
        	if(root == NULL)return true;
        	//计算树高——黑色结点个数,比较左右子树的树高是否相同
        	int l = getNum(root->lchild);
        	int r = getNum(root->rchild);
        	if(l != r)return false; 
        	//带返回条件的递归函数
        	return judge2(root->lchild) && judge2(root->rchild); 
        }
        int main(){
        	int n, k;
        	cin >> k; 
        	for(int i = 0; i < k; i++){
        		cin >> n;
        		v.resize(n);
        		//在读取结点的过程中,建树
        		node *root = NULL; 
        		for(int j = 0; j < n; j++){
        			cin >> v[j];
        			root = build(root, v[j]);//建立二叉搜索树 
        		}
        		//判断是否是红黑树
        		//不是红黑树 
        		if(v[0] < 0 || !judge1(root) || !judge2(root)){
        			printf("No\n"); 
        		} else printf("Yes\n");
        	}
        	return 0;
        } 
        
  • 并查集

    • 合并有相同爱好的人,输出集合的个数以及每个集合有多少人【PAT A 1107】

      • 思路:

        ①既然要求的是人数,那么就将爱好作为合并条件,合并人。可以开一个数组hobby,爱好编号作为数组下标,人编号作为数组值。然后每读取一个爱好,判断该爱好是否其他人也有,没有就将该爱好的值记为当前人的编号。之后合并当前人的编号与hobby数组值。 这里会出现两种情况,一种是与自身合并,也就是i = hobby[temp];另一种是与有相同爱好的其他人合并。

        ②计算每个集合中人的个数通用模板

        //计算每个集合人数
        	for(int i = 1; i <= n; i++){
        		isRoot[findFather(i)]++;
        	} 
        

        ③计算总共有多少集合通用模板:

        int ans = 0;
        for(int i = 1; i <= n; i++){
            if(isRoot[i] != 0)ans++;
        }
        
      • 代码实现:

        #include<bits/stdc++.h>
        using namespace std; 
        int hobby[1010] = {0}, father[1010], isRoot[1010] = {0};
        int findFather(int x){
        	if(x == father[x])return x;
        	else{
        		int F = findFather(father[x]);
        		father[x] = F;
        		return F;
        	}
        }
        void Union(int a, int b){
        	int fa = findFather(a);
        	int fb = findFather(b);
        	if(fa != fb){
        		father[fa] = fb;
        	} 
        }
        bool cmp(int a, int b){
        	return a > b;
        }
        int main(){
        	
        	int n, k, temp;
        	cin >> n;
        	//初始化father数组
        	for(int i = 1; i <= n; i++)father[i] = i;
        	for(int i = 1; i <= n; i++){
        		scanf("%d:", &k);
        		while(k--){
        			cin >> temp;
        			if(hobby[temp]==0)
        				hobby[temp] = i; //将爱好与人编号对应起来,点睛之笔
        			Union(i, hobby[temp]);//将当前人与有相同爱好的人合并到一个集合中 
        		}
        	}
        	//计算每个集合人数
        	for(int i = 1; i <= n; i++){
        		isRoot[findFather(i)]++;
        	} 
        	//计算有多少个集合
        	int ans = 0;
        	for(int i = 1; i <= n; i++){
        		if(isRoot[i] != 0)ans++;
        	} 
        	sort(isRoot+1, isRoot + n + 1, cmp);//降序排序
        	//输出结果
        	printf("%d\n", ans);
        	for(int i = 1; i <= ans; i++){
        		printf("%d", isRoot[i]);
        		if(i != ans)printf(" ");
        	} 
        	return 0;
        } 
        
  • 堆(基础操作还是不熟悉,再多重复几遍)

    • 建堆,堆排序;插入排序【PAT A 1098】

      • 思路:

        ①本题难点在于自己对堆的基础操作不熟悉。首先是建堆的概念,建堆完成不是初始序列的形式,而是初始序列经过向下调整之后完成的大顶堆。

        ②堆排序,通常是指已经建立完成大顶堆。然后需要将该堆变成升序序列,注意,升序序列不等于小顶堆。

      • 代码实现

        #include<bits/stdc++.h>
        using namespace std;
        int n, ori[110], tempori[110], ans[110]; 
        bool isSame(int a[], int b[]){
        	for(int i = 1; i <= n; i++){
        		if(a[i] != b[i])return false;
        	}
        	return true;
        }
        bool insertSort(){
        	int flag = 0;
        	for(int i = 2; i <= n; i++){
        		if(i != 2 && isSame(tempori, ans)){
        			flag = 1;
        		}
        		//插入排序
        		sort(tempori+1, tempori + i + 1); 
        		if(flag){
        			sort(ans+1, ans + i + 1);
        			return true;
        		}
        	}
        	return false;
        }
        //建立的是堆顶为最大值的堆 
        void downAdjust(int low, int high){
        	int i = low, j = i * 2;
        	while(j <= high){
        		//寻找最大孩子结点
        		if(j+1 <= high && ori[j+1] > ori[j]){
        			j = j + 1;
        		} 
        		//向下调整
        		if(ori[j] > ori[i]){
        			swap(ori[j], ori[i]);
        			i = j;
        			j = i * 2;
        		}else{
        			break;
        		}
        	}
        }
        void create(){
        	for(int i = n / 2; i >= 1; i--){
        		downAdjust(i, n);
        	}
        }
        void heapSort(){
        	//建堆
        	create();
        	for(int i = n; i > 1; i--){
        		swap(ori[i], ori[1]);
        		downAdjust(1, i-1);
        		if(isSame(ori, ans)){
        			swap(ori[i-1], ori[1]);
        			downAdjust(1, i-2);
        			return;
        		}
        	} 
        }
        int main(){
        	cin >> n;
        	for(int i = 1; i <= n; i++){
        		cin >> ori[i];
        		tempori[i] = ori[i];
        	}
        	for(int i = 1; i <= n; i++){
        		cin >> ans[i]; 
        	}
        	//判断是否是插入排序
        	if(insertSort()){
        		printf("Insertion Sort\n");
        		for(int i = 1; i <= n; i++){
        			printf("%d", ans[i]);
        			if(i != n)printf(" ");
        		}
        	} else{
        		printf("Heap Sort\n");
        		//堆排序
        		heapSort(); 
        		for(int i = 1; i <= n; i++){
        			printf("%d", ori[i]);
        			if(i != n)printf(" ");
        		}
        	}
        	return 0;
        } 
        
    • 判断是否是Min堆或者Max堆

      • 模板代码如下:

        int isMin = 1, isMax = 1, a[maxn];
        for(int i = 2; i <= n; i++){
            if(a[i/2] > a[i])isMin = 0;
            if(a[i/2] < a[i])isMax = 0;
        }
        if(isMin == 1)printf("Min Heap\n");
        else if(isMax == 1)printf("Max Heap\n");
        else printf("Not Heap\n");
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦想总比行动多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值