算法基础——字符串相关

算法基础——字符串相关

目录:

  1. 基础知识
    1. STL-string常用函数
    2. KMP算法
  2. 应用实例
    1. 特殊乘法【清华大学】
    2. 密码翻译【北京大学】
    3. 简单密码【北京大学】
    4. 统计字符【浙江大学】
    5. 字母统计【上海交通大学】
    6. 统计字符【2017校招真题在线编程】
    7. skew数【北京大学】
    8. 单词替换【北京大学】
    9. 首字母大写【北京大学】
    10. 浮点数加法【北京大学】
    11. 后缀子串排序【上海交通大学】
    12. 字符串匹配【北京航天航空大学】
    13. String Matching【上海交通大学】

一、基础知识

1、STL-string常用函数:

  • string的长度:
    • length():返回当前字符串长度。
    • size():返回当前字符串长度。
  • string的元素访问:
    • 可以像数组那样通过元素下标进行访问,下标从0到size() - 1。
      • for(int i = 0; i < str.size(); i++){
      •     cout << str[i];
      • }
      • cout << endl;
    • 可以通过迭代器进行访问,迭代器类似于指针。
      • for(string::iterator iter = str.begin(); iter != str.end(); iter++){
      •     cout << &iter;
      • }
      • cout << endl;
  • string的元素操作:
    • insert(loc, "abcd"):将abcd从第loc位置(最小loc为0)开始插入。
    • erase(loc):将str串从第loc位置(最小loc为0)开始删除,一直删到str结尾。
    • erase(loc, 4):将str串从第loc位置(最小loc为0)开始删除,删除四个字符。
    • clear():将字符串清空。
  • 寻找特定字符或字符串:
    • find(字符或字符串):找到相应的字符或字符串则返回对应的下标,若找不到则返回string::npos。
  • 返回字符串的子串:
    • substr(3, 5):从第3位置(最小为0)开始,返回长度为5的字符串。

2、KMP算法(具体代码博主看了好几遍也还没看懂,抄的王道o(╥﹏╥)o,见应用实例中题13):

  • 核心思想:模式串失配后,并不是从下一个字符开始重新匹配,而是利用已有的信息,跳过一些不可能成功的匹配,以便尽量减少模式串与主串的匹配次数,进而达到快速匹配的目的。
  • 名词定义:
    • next数组(前缀数组):记录字符串匹配过程中失配可以向前多跳的字符个数。
    • 前缀:除最后一个字符外,字符串的所有头部子串。
    • 后缀:除第一个字符外,字符串的所有尾部子串。
    • 部分匹配值:字符串前缀和后缀最长相等前后缀的长度。
  • 移动位数 = 已匹配的字符数 - 对应的部分匹配值

  • 时间复杂度:O(n + m)
  • 遇到第一个匹配的地方后,停止搜索,输出位置,代码如下:
#include <iostream>
#include <string>

using namespace std;

const int MAX_N = 10000;
int nextTable[MAX_N];

void GetNext(string pattern){
	int j = 0;
	nextTable[j] = -1;
	int i = nextTable[j];
	while(j < pattern.size()){
		if(i == -1 || pattern[j] == pattern[i]){
			i++;
			j++;
			nextTable[j] = i;
		}else{
			i = nextTable[i];
		}
	}
}

int KMP(string text, string pattern){
	GetNext(pattern);
	int i = 0, j = 0;
	while(i < text.size() && j < pattern.size()){
		if(j == -1 || text[i] == pattern[j]){
			i++;
			j++;
		}else{
			j = nextTable[j];
		}
	}
	if(j == pattern.size()){
		return i - j + 1;
	}else{
		return -1;
	}
}

int main(){
	int nextTable[MAX_N];
	memset(nextTable, 0, sizeof(nextTable));
	string s1, s2;
	while(cin >> s1 >> s2){
		cout << KMP(s1, s2) << endl;
	}
	return 0;
}

二、应用实例

1、题目描述:写个算法,对2个小于1000000000的输入,求结果。 特殊乘法举例:123 * 45 = 1*4 +1*5 +2*4 +2*5 +3*4+3*5【清华大学】

  • 输入格式:两个小于1000000000的数
  • 输出格式:输入可能有多组数据,对于每一组数据,输出Input中的两个数按照题目要求的方法进行运算后得到的结果。
  • 样例输入:
    • 123 45
  • 样例输出:
    • 54

示例代码:

#include <iostream>
#include <string>

using namespace std;

int main(){
	string str1, str2;
	while(cin >> str1 >> str2){
		int count = 0;
		for(int i = 0; i < str1.size(); i++){
			for(int j = 0; j < str2.size(); j++){
				count += (str1[i] - '0') * (str2[j] - '0');
			}
		}
		cout << count << endl;
	}
	return 0;
}

2、题目描述:在情报传递过程中,为了防止情报被截获,往往需要对情报用一定的方式加密,简单的加密算法虽然不足以完全避免情报被破译,但仍然能防止情报被轻易的识别。我们给出一种最简的的加密方法,对给定的一个字符串,把其中从a-y,A-Y的字母用其后继字母替代,把z和Z用a和A替代,则可得到一个简单的加密字符串。【北京大学】

  • 输入格式:读取这一行字符串,每个字符串长度小于80个字符
  • 输出格式:对于每组数据,输出每行字符串的加密字符串。
  • 样例输入:
    • Hello! How are you!
  • 样例输出:
    • Ifmmp! Ipx bsf zpv!

示例代码:

#include <iostream>
#include <string>

using namespace std;

void Code(string s){
	for(int i = 0; i < s.size(); i++){
		if(s[i] == 'z' || s[i] == 'Z'){
			s[i] -= 25;
		}else if((s[i] >= 'a' && s[i] <= 'y')
			|| (s[i] >= 'A' && s[i] <= 'Y')){
			s[i] += 1;
		}
	}
	cout << s << endl;
}

int main(){
	string s;
	while(getline(cin ,s)){
		Code(s);
	}
	return 0;
}

3、题目描述:Julius Caesar曾经使用过一种很简单的密码。 对于明文中的每个字符,将它用它字母表中后5位对应的字符来代替,这样就得到了密文。 比如字符A用F来代替。如下是密文和明文中字符的对应关系。 密文 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 明文 V W X Y Z A B C D E F G H I J K L M N O P Q R S T U 你的任务是对给定的密文进行解密得到明文。 你需要注意的是,密文中出现的字母都是大写字母。密文中也包括非字母的字符,对这些字符不用进行解码。【北京大学】

  • 输入格式:输入中的测试数据不超过100组。每组数据都有如下的形式,而且各组测试数据之间没有空白的行。
    一组测试数据包括三部分:
    1.    起始行 - 一行,包括字符串 "START" 
    2.    密文 - 一行,给出密文,密文不为空,而且其中的字符数不超过200
    3.    结束行 - 一行,包括字符串 "END" 
    在最后一组测试数据之后有一行,包括字符串 "ENDOFINPUT"。
  • 输出格式:对每组数据,都有一行输出,给出密文对应的明文。
  • 样例输入:
    • START
    • NS BFW, JAJSYX TK NRUTWYFSHJ FWJ YMJ WJXZQY TK YWNANFQ HFZXJX
    • END
    • START
    • N BTZQI WFYMJW GJ KNWXY NS F QNYYQJ NGJWNFS ANQQFLJ YMFS XJHTSI NS WTRJ
    • END
    • START
    • IFSLJW PSTBX KZQQ BJQQ YMFY HFJXFW NX RTWJ IFSLJWTZX YMFS MJ
    • END
    • ENDOFINPUT
  • 样例输出:
    • IN WAR, EVENTS OF IMPORTANCE ARE THE RESULT OF TRIVIAL CAUSES
    • I WOULD RATHER BE FIRST IN A LITTLE IBERIAN VILLAGE THAN SECOND IN ROME
    • DANGER KNOWS FULL WELL THAT CAESAR IS MORE DANGEROUS THAN HE

示例代码:

#include <iostream>
#include <string>

using namespace std;

int main(){
	string s;
	while(getline(cin, s) && s != "ENDOFINPUT"){
		getline(cin, s);
		for(int i = 0; i < s.size(); i++){
			if(s[i] >= 'F' && s[i] <= 'Z'){
				s[i] -= 5;
			}else if(s[i] >= 'A' && s[i] <= 'E'){
				s[i] += 21;
			}
		}
		cout << s << endl;
		getline(cin, s);
	}
	return 0;
}

4、题目描述:统计一个给定字符串中指定的字符出现的次数。【浙江大学】

  • 输入格式:测试输入包含若干测试用例,每个测试用例包含2行,第1行为一个长度不超过5的字符串,第2行为一个长度不超过80的字符串。注意这里的字符串包含空格,即空格也可能是要求被统计的字符之一。当读到'#'时输入结束,相应的结果不要输出。
  • 输出格式:对每个测试用例,统计第1行中字符串的每个字符在第2行字符串中出现的次数,按如下格式输出:
    c0 n0
    c1 n1
    c2 n2
    ...
    其中ci是第1行中第i个字符,ni是ci出现的次数。
  • 样例输入:
    • I
    • THIS IS A TEST
    • i ng
    • this is a long test string
    • #
  • 样例输出:
    • I 2
    • i 3
    •   5
    • n 2
    • g 2

示例代码1:(4ms,504k)

#include <iostream>
#include <string>

using namespace std;

int main(){
	string searchStr;
	string inputStr;
	while(getline(cin, searchStr) && searchStr != "#"){
		getline(cin, inputStr);
		for(int i = 0; i < searchStr.size(); i++){
			int count = 0;
			for(int j = 0; j < inputStr.size(); j++){
				if(inputStr[j] == searchStr[i]){
					count++;
				}
			}
			cout << searchStr[i] << " " << count << endl;
		}
	}
	return 0;
}

示例代码2:(4ms,500k)

#include <iostream>
#include <string>
#include <cstring>

using namespace std;
int a[128];

int main(){
	string searchStr;
	string inputStr;
	while(getline(cin, searchStr) && searchStr != "#"){
		memset(a, 0, sizeof(a));
		getline(cin, inputStr);
		for(int j = 0; j < inputStr.size(); j++){
			a[inputStr[j]]++;
		}
		for(int i = 0; i < searchStr.size(); i++){
			cout << searchStr[i] << " " << a[searchStr[i]] << endl;
		}
	}
	return 0;
}

5、题目描述:输入一行字符串,计算其中A-Z大写字母出现的次数【上海交通大学】

  • 输入格式:案例可能有多组,每个案例输入为一行字符串。
  • 输出格式:对每个案例按A-Z的顺序输出其中大写字母出现的次数。
  • 样例输入:
    • DFJEIWFNQLEF0395823048+_+JDLSFJDLSJFKK
  • 样例输出:
    • A:0
      B:0
      C:0
      D:3
      E:2
      F:5
      G:0
      H:0
      I:1
      J:4
      K:2
      L:3
      M:0
      N:1
      O:0
      P:0
      Q:1
      R:0
      S:2
      T:0
      U:0
      V:0
      W:1
      X:0
      Y:0
      Z:0

示例代码:

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

int a[26];

int main(){
	string s;
	while(getline(cin, s)){
		memset(a, 0, sizeof(a));
		for(int i = 0; i < s.size(); i++){
			if(s[i] >= 'A' && s[i] <= 'Z'){
				a[s[i] - 'A']++;
			}
		}
		for(int i = 0; i < 26; i++){
			cout << char('A' + i) << ":" << a[i] << endl;
		}
	}

	return 0;
}

6、题目描述:给定一个英文字符串,请写一段代码找出这个字符串中首先出现三次的那个英文字符(需要区分大小写)。【2017校招真题在线编程】

  • 输入格式:输入数据一个字符串,包括字母,数字等。
  • 输出格式:输出首先出现三次的那个英文字符
  • 样例输入:
    • Have you ever gone shopping and
  • 样例输出:
    • 3

示例代码:

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

int a[128];

int main(){
	string s;
	while(getline(cin, s)){
		memset(a, 0, sizeof(a));
		for(int i = 0; i < s.size(); i++){
			if((s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z')){
				a[s[i]]++;
				if(a[s[i]] == 3){
					cout << s[i] << endl;
					break;
				}
			}
		}
	}
	return 0;
}

7、题目描述:在 skew binary表示中, 第 k 位的值x[k]表示x[k]*(2^(k+1)-1)。 每个位上的可能数字是0 或 1,最后面一个非零位可以是2, 例如, 10120(skew) = 1*(2^5-1) + 0*(2^4-1) + 1*(2^3-1) + 2*(2^2-1) + 0*(2^1-1) = 31 + 0 + 7 + 6 + 0 = 44. 前十个skew数是 0、1、2、10、11、12、20、100、101、以及102。【北京大学】

  • 输入格式:输入包含一行或多行,每行包含一个整数n。如果 n = 0 表示输入结束,否则n是一个skew数
  • 输出格式:可能有多组测试数据,对于每一个输入,输出它的十进制表示。转换成十进制后, n 不超过 2^31-1 = 2147483647
  • 样例输入:
    • 10120
    • 200000000000000000000000000000
    • 10
    • 1000000000000000000000000000000
    • 11
    • 100
    • 11111000001110000101101102000
    • 0
  • 样例输出:
    • 44
    • 2147483646
    • 3
    • 2147483647
    • 4
    • 7
    • 1041110737

示例代码:

#include <iostream>
#include <string>

using namespace std;

int main(){
	string s;
	while(cin >> s && s != "0"){
		long long count = 0;
		long long tmp = 2;
		for(int i = s.size() - 1; i >= 0; i--){
			count += (s[i] - '0') * (tmp - 1);
			tmp *= 2;
		}
		cout << count << endl;
	}
	return 0;
}

8、题目描述:输入一个字符串,以回车结束(字符串长度<=100)。该字符串由若干个单词组成,单词之间用一个空格隔开,所有单词区分大小写。现需要将其中的某个单词替换成另一个单词,并输出替换之后的字符串。【北京大学】

  • 输入格式:多组数据。每组数据输入包括3行,第1行是包含多个单词的字符串 s,第2行是待替换的单词a(长度<=100)。第3行是a将被替换的单词b(长度<=100)。s, a, b 最前面和最后面都没有空格.
  • 输出格式:每个测试数据输出只有 1 行,将s中所有单词a替换成b之后的字符串。
  • 样例输入:
    • You want someone to help you
    • You
    • I
  • 样例输出:
    • I want someone to help you

示例代码:

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

int main(){
	string inputStr, originWord, replaceWord;
	while(getline(cin, inputStr)){ 
		getline(cin, originWord);
		getline(cin, replaceWord);
		int index = 0;
		string word = "";
		while(index <= inputStr.size() - 1){
			if(index != 0){
				cout << " ";
			}
			word = "";
			while(index <= inputStr.size() - 1 && isalpha(inputStr[index])){
				word += inputStr[index++];
			}
			if(word == originWord){
				cout << replaceWord;
			}else{
				cout << word;
			}
			index++;
		}
		cout << endl;
	}
	return 0;
}

9、题目描述:对一个字符串中的所有单词,如果单词的首字母不是大写字母,则把单词的首字母变成大写字母。 在字符串中,单词之间通过空白符分隔,空白符包括:空格(' ')、制表符('\t')、回车符('\r')、换行符('\n')。【北京大学】

  • 输入格式:输入一行:待处理的字符串(长度小于100)。
  • 输出格式:可能有多组测试数据,对于每组数据,输出一行:转换后的字符串。
  • 样例输入:
    • if so, you already have a google account. you can sign in on the right.
  • 样例输出:
    • If So, You Already Have A Google Account. You Can Sign In On The Right.

示例代码:

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

int main(){
	string s;
	while(getline(cin, s)){
		int index = 0;
		string word;
		while(index <= s.size() - 1){
			if(s[index] == ' ' || s[index] == '\t' || s[index] == '\r' || s[index] == '\n'){
				cout << s[index++];
				continue;
			}
			word = "";
			while(index <= s.size() - 1 && s[index] != ' '&&  s[index] != '\t' && s[index] != '\r' && s[index] != '\n'){
				word += s[index++];
			}
			word[0] = toupper(word[0]);
			cout << word;
		}
		cout << endl;
	}
	return 0;
}

10、题目描述:求2个浮点数相加的和 题目中输入输出中出现浮点数都有如下的形式: P1P2...Pi.Q1Q2...Qj 对于整数部分,P1P2...Pi是一个非负整数 对于小数部分,Qj不等于0【北京大学】

  • 输入格式:对于每组案例,每组测试数据占2行,分别是两个加数。
  • 输出格式:每组案例是n行,每组测试数据有一行输出是相应的和。输出保证一定是一个小数部分不为0的浮点数
  • 样例输入:
    • 0.111111111111111111111111111111
    • 0.111111111111111111111111111111
  • 样例输出:
    • 0.222222222222222222222222222222

示例代码:

#include <iostream>
#include <string>

using namespace std;

int main(){
	string s1, s2;
	int pointLoc1, pointLoc2;
	while(cin >> s1 >> s2){
		if(s1.find('.') == s1.npos){
			pointLoc1 = s1.size();
		}else{
			pointLoc1 = s1.find('.');
		}
		if(s2.find('.') == s2.npos){
			pointLoc2 = s2.size();
		}else{
			pointLoc2 = s2.find('.');
		}
		int distance = pointLoc1 - pointLoc2;
		int distance2 = s1.size() - pointLoc1 - s2.size() + pointLoc2;
		string tmp = "", tmp2 = "";
		for(int i = 0; i < abs(distance); i++){
			tmp += "0";
		}
		for(int i = 0; i < abs(distance2); i++){
			tmp2 += "0";
		}
		if(pointLoc1 > pointLoc2){
			s2 = tmp + s2;
		}else{
			s1 = tmp + s1;
		}
		if(distance2 > 0){
			s2 += tmp2;
		}else{
			s1 += tmp2;
		}
		int carry = 0;
		for(int i = s1.size() - 1; i >= 0; i--){
			if(s1[i] == '.'){
				continue;
			}
			int current = carry + s1[i] - '0' + s2[i] - '0';
			carry = current / 10;
			s1[i] = current % 10 + '0';
		}
		if(carry != 0){
			char c = carry + '0';
			s1 = c + s1;
		}
		cout << s1 << endl;
	}
	return 0;
}

11、题目描述:对于一个字符串,将其后缀子串进行排序,例如grain 其子串有: grain rain ain in n 然后对各子串按字典顺序排序,即: ain,grain,in,n,rain【上海交通大学】

  • 输入格式:每个案例为一行字符串。
  • 输出格式:将子串排序输出
  • 样例输入:
    • grain
  • 样例输出:
    • ain
    • grain
    • in
    • n
    • rain

示例代码:

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

using namespace std;

vector<string> myVector;

int main(){
	string s;
	while(cin >> s){
		for(int i = 0; i < s.size(); i++){
			myVector.push_back(s.substr(i));
		}
		sort(myVector.begin(), myVector.end());
		for(int i = 0; i < myVector.size(); i++){
			cout << myVector[i] << endl;
		}
		myVector.clear();
	}
	return 0;
}

12、题目描述:读入数据string[ ],然后读入一个短字符串。要求查找string[ ]中和短字符串的所有匹配,输出行号、匹配字符串。匹配时不区分大小写,并且可以有多个用中括号表示的模式匹配。如“aa[123]bb”,就是说aa1bb、aa2bb、aa3bb都算匹配。【北京航天航空大学】

  • 输入格式:输入有多组数据。每组数据第一行输入n(1<=n<=1000),从第二行开始输入n个字符串(不含空格),接下来输入一个匹配字符串。
  • 输出格式:输出匹配到的字符串的行号和该字符串(匹配时不区分大小写)。
  • 样例输入:
    • 4
    • Aab
    • a2B
    • ab
    • ABB
    • a[a2b]b
  • 样例输出:
    • 1 Aab
    • 2 a2B
    • 4 ABB

示例代码:

#include <iostream>
#include <vector>
#include <string>
#include <queue>

using namespace std;

vector<string> myVector;
vector<string> resultVector;
vector<string> resultPattern;
queue<string> tmpPattern;

void Getpattern(){
	while(!tmpPattern.empty()){
		string s = tmpPattern.front();
		tmpPattern.pop();
		int begin = s.find('['), end = s.find(']');
		if(begin != s.npos){
			string patternStr = s.substr(begin + 1, end - begin - 1);
			s.erase(begin, end - begin + 1);
			for(int i = 0; i < patternStr.size(); i++){
				string sCopy = s;
				string tmp = "";
				tmpPattern.push(sCopy.insert(begin, tmp + patternStr[i]));
			}
		}else{
			resultPattern.push_back(s);
		}
	}
}

int main(){
	int n;
	string s;
	while(cin >> n){
		for(int i = 0; i < n; i++){
			cin >> s;
			resultVector.push_back(s);
			for(int j = 0; j < s.size(); j++){
				s[j] = tolower(s[j]);
			}
			myVector.push_back(s);
		}
		cin >> s;
		for(int j = 0; j < s.size(); j++){
			s[j] = tolower(s[j]);
		}
		tmpPattern.push(s);
		Getpattern();
		for(int i = 0; i < myVector.size(); i++){
			for(int j = 0; j < resultPattern.size(); j++){
				if(myVector[i].find(resultPattern[j]) != myVector[i].npos){
					cout << i + 1 << " " << resultVector[i] << endl;
					break;
				}
			}
		}
		myVector.clear();
		resultVector.clear();
		resultPattern.clear();
	}
	return 0;
}

13、题目描述: Finding all occurrences of a pattern in a text is a problem that arises frequently in text-editing programs.     Typically,the text is a document being edited,and the pattern searched for is a particular word supplied by the user.       We assume that the text is an array T[1..n] of length n and that the pattern is an array P[1..m] of length m<=n.We further assume that the elements of P and  T are all alphabets(∑={a,b...,z}).The character arrays P and T are often called strings of characters.       We say that pattern P occurs with shift s in the text T if 0<=s<=n and T[s+1..s+m] = P[1..m](that is if T[s+j]=P[j],for 1<=j<=m).       If P occurs with shift s in T,then we call s a valid shift;otherwise,we calls a invalid shift.      Your task is to calculate the number of vald shifts for the given text T and p attern P.【上海交通大学】

  • 输入格式:For each case, there are two strings T and P on a line,separated by a single space.You may assume both the length of T and P will not exceed 10^6.
  • 输出格式:You should output a number on a separate line,which indicates the number of valid shifts for the given text T and pattern P.
  • 样例输入:
    • abababab abab
  • 样例输出:
    • 3

示例代码1:

#include <iostream>
#include <string>

using namespace std;

int main(){
	string s1, s2;
	while(cin >> s1 >> s2){
		int count = 0;
		int pos = s1.find(s2);
		while(pos != s1.npos){
			count++;
			s1 = s1.substr(pos + 1);
			pos = s1.find(s2);
		}
		cout << count << endl;
	}
	return 0;
}

示例代码2:(KMP)

#include <iostream>
#include <string>

using namespace std;

const int MAX_N = 1000010;

int nextTable[MAX_N];

void GetNext(string pattern){
	int j = 0;
	nextTable[j] = -1;
	int i = nextTable[j];
	while(j < pattern.size()){
		if(i == -1 || pattern[j] == pattern[i]){
			i++;
			j++;
			nextTable[j] = i;
		}else{
			i = nextTable[i];
		}
	}
}

int KMP(string text, string pattern){
	GetNext(pattern);
	int i = 0, j = 0, number = 0;
	while(i < text.size()){
		if(j == -1 || text[i] == pattern[j]){
			i++;
			j++;
		}else{
			j = nextTable[j];
		}
		if(j == pattern.size()){
			number++;
			j = nextTable[j];
		}
	}
	return number;
}

int main(){
	string s1, s2;
	while(cin >> s1 >> s2){
		cout << KMP(s1, s2) << endl;
	}
	return 0;
}

参考文献:

[1]Thomas.H.Cormen Charles E. Leiseron、Ronald L. Rivest Clifford Srein. 算法导论(第3版). [M]北京:机械工业出版社,2013.01;
[2]杨泽邦、赵霖. 计算机考研——机试指南(第2版). [M]北京:电子工业出版社,2019.11;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值