HW2016_字符串_STL_DP
一、在字符串str1中删除那些在str2中出现的字符。
str2可能会有重复字符,直接遍历会导致效率低下,故先借助STL的set容器对str1查重;
然后,遍历str1和str2,对str1进行查重。
#include <iostream> #include <string> #include <set> using namespace std; void deleteChar(char* strRet, const string& str1,int len1, const string& str2,int len2) { if(len1 < 1) //异常检测 { return; } bool findIt = false; //查找标记位 set<char>mySet; int i = 0,j = 0,k = 0; for(i = 0; i < len2; ++i) //str2去重复字符 { mySet.insert(str2[i]); } for(j = 0; j < len1; j++) { for(set<char>::iterator it = mySet.begin(); it != mySet.end(); ++it) { if(str1[j] == *it && findIt == false) { findIt = true; break; } }//end for if(!findIt) { strRet[k++] = str1[j]; } findIt = false; //标记位置位 }//end for strRet[k] = '\0'; //c风格字符串结束标志 } int main() { string str1,str2; while(cin >> str1 >> str2) { int len1 = str1.size(); int len2 = str2.size();
char* strRet = new char[len1 + 1]; //申请空间存放查重后的字符串 deleteChar(strRet,str1,len1,str2,len2); cout << strRet << endl; delete strRet; //防止内存泄漏 return 0; } }
二、
编程题-成绩排名
题目总共包含如下两种格式的字符串命令:
1 LOD GRADE命令,其格式为:
LOD GRADE:NAME=XiaoMing,MATH=80,LANG=90;
(1)此命令用于导入学生成绩
(2)NAME字段表示学生姓名
(3)MATH字段表示学生数学成绩
(4)LANG字段表示学生语文成绩
(5)MATH字段和LANG字段顺序不一定是MATH在前,LANG在后
(6)相同的分数,名词相同,后面的名次孔雀:例如100,99,99,99,98,98,名次1,2,2,2,5,5
(7)此命令会连续执行,直到遇到第一个LST GRADE
2 LST GRADE命令,其格式为:
LST GRADE:NAME=XiaoHong;
(1)此命令用于查询学生成绩
(2)NAME字段表示学生姓名
(3)查询结果格式:姓名 数学 语文 总分 数学排名 语文排名 总排名
(4)每组用例,此命令仅执行一次
样例输入
LOD GRADE:NAME=XiaoMing,MATH=80,LANG=90;
LOD GRADE:NAME=XiaoHong,LANG=60,MATH=100;
LOD GRADE:NAME=XiaoMei,MATH=70,LANG=90;
LST GRADE:NAME=XiaoHong;
样例输出 XiaoHong 100 60 160 1 3 2
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <cstdlib> using namespace std; const string LOD = "LOD GRADE"; const string LST = "LST GRADE"; int myCout = 0; class student{ public: student(string str) { OPE = ""; unsigned int posOPE = str.find_first_of(':'); if( posOPE < str.size()) OPE = str.substr(0, posOPE); unsigned int posNAME1 = str.find_first_of('='); unsigned int posNAME2 = str.find_first_of(','); NAME = str.substr(posNAME1 + 1, posNAME2 - posNAME1 - 1); unsigned int posEnd = str.find_last_of(';'); unsigned int posMATH = str.find_last_of('H'); unsigned int posLANG = str.find_last_of('G'); unsigned int posLastCommer = str.find_last_of(','); if(posEnd - posMATH > 5) { MATH = atoi(str.substr(posMATH + 2, posLastCommer - posMATH - 2).c_str()); LANG = atoi(str.substr(posLastCommer + 6, posEnd - posLastCommer -6).c_str()); } else { MATH = atoi(str.substr(posMATH + 2, posEnd - posMATH - 2).c_str()); LANG = atoi(str.substr(posLANG + 2, posLastCommer - posLANG - 2).c_str()); } totalScore = MATH + LANG; mathMarking = 0; langMarking = 0; totalMarking = 0; count = 0; } ~student(){} string OPE; string NAME; int MATH; int LANG; int totalScore; int mathMarking; int langMarking; int totalMarking; int count; }; bool mathCompare(student*& stu1, student*& stu2) { return (stu1->MATH > stu2->MATH) || (stu1->MATH == stu2->MATH && stu1->count < stu2->count); //desc ; 成绩相等,按照出现的顺序排序 } bool langCompare(student*& stu1, student*& stu2) { return (stu1->LANG > stu2->LANG) || (stu1->LANG == stu2->LANG && stu1->count < stu2->count); //desc } bool totalCompare(student*& stu1, student*& stu2) { return (stu1->totalScore > stu2->totalScore) || (stu1->totalScore == stu2->totalScore && stu1->count < stu2->count); //desc } int main() { string str; vector<student* >students; while(getline(cin, str)) //去读一行,使用cin>>会有缓冲区的问题(空格,tab,回车) { //fill into vector student* stu = new student(str); if(LOD == stu->OPE) { students.push_back(stu); stu->count = myCout++; //用于记录学生出现的顺序 } if(LST == stu->OPE) { string stuName = ""; //提取学生姓名,用于匹配查找 unsigned int posNAME01 = str.find_last_of('='); unsigned int posNAME02 = str.find_last_of(';'); stuName = str.substr(posNAME01 + 1, posNAME02 - posNAME01 - 1); sort(students.begin(),students.end(),mathCompare); for(int i = 0; i < students.size();++i) { if(students[i]->NAME == stuName) students[i]->mathMarking = i+1; //根据数学成绩排序规则,给学生的数学排名赋值 } sort(students.begin(),students.end(),langCompare); for(int i = 0; i < students.size();++i) { if(students[i]->NAME == stuName) students[i]->langMarking = i+1; } sort(students.begin(),students.end(),totalCompare); for(int i = 0; i < students.size();++i) { if(students[i]->NAME == stuName) students[i]->totalMarking = i+1; } for(int i = 0; i < students.size();++i) { if(students[i]->NAME == stuName) //输出查找学生的信息 cout << students[i]->NAME << " " << students[i]->MATH << " " << students[i]->LANG << " " << students[i]->totalScore << " " << students[i]->mathMarking << " " << students[i]->langMarking << " " <<students[i]->totalMarking; } } }//while return 0; }
三、
给出两个字符串A,B。将A字符串转化为B字符串,转化共两种方式:删除连续的n个字符,一次操作费用为2。增加连续的n个字符(增加的什么由你决定),一次操作的费用为n+2。求把A变为B最小费用。
输入:第一行输入一个正整数(1<=T<=10),表示有T组测试数据。
对于每组测试数据:
两行字符串A,B(字符串长度不超过2000,字符仅包含小写字母。)
输出:对于每组测试数据,输出一行一个整数,表示最小费用。
样例输入
2
dsafsadfadf
fdfd
aaaaaaaa
bbbbbbbb
样例输出:
7
12
分析:参考知乎(时间复杂度O(N3)),后面自己有时间复杂度O(N2)的方法。
1. 不修改, 只有当str1[j - 1] == str2[i - 1]的情况才可能存在, 此时费用等于将A[0:i-1]变换为B[0:j-1]的最小费用(三种方式中最小的那个),否则为INF
2. 添加结尾, 考虑添加的长度为k,此时费用为将A[0:i]变换成B[0:j-k]再加上一个根据结尾不同变换的COST1
3. 删除结尾, 考虑删除的长度为k,此时费用为将A[0:i-k]变换为B[0:j]再加上一个根据结尾不同变换的COST2
( Insert: Min(F(n,0)+m,...,F(n, m-1)+1)+2;)
作者:AbmiP 链接:https://www.zhihu.com/question/50960106/answer/123577803 来源:知乎 著作权归作者所有,转载请联系作者获得授权。 #define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define INF 3000 using namespace std; int de[2010][2010], ae[2010][2010], ne[2010][2010]; char s1[2010], s2[2010]; int main() { //freopen("io/in.txt", "r", stdin);freopen("io/out.txt", "w", stdout); int n, l1, l2; char c; scanf("%d%c", &n, &c); while (n--) { char* tmp = s1; char c; while ((scanf("%c", &c) != EOF) && c != '\n')*(tmp++) = c; *tmp = '\0'; tmp = s2; while ((scanf("%c", &c) != EOF) && c != '\n')*(tmp++) = c; *tmp = '\0'; l1 = strlen(s1); l2 = strlen(s2); for (int i = 0; i <= l1; i++) { de[0][i] = 2; ae[0][i] = ne[0][i] = INF; } for (int i = 0; i <= l2; i++) { ae[i][0] = i + 2; de[i][0] = ne[i][0] = INF; } ne[0][0] = 0; for (int j = 1; j <= l2; j++) for (int i = 1; i <= l1; i++) { ne[j][i] = s1[i - 1] == s2[j - 1] ? min(min(ne[j-1][i-1], ae[j-1][i-1]), de[j-1][i-1]) : INF; ae[j][i] = de[j][i] = INF; for (int k = 1; k <= j; k++) ae[j][i] = min(ae[j][i], min(ae[j - k][i] + k, min(de[j - k][i] + k + 2, ne[j - k][i] + k + 2))); for (int k = 1; k <= i; k++) de[j][i] = min(de[j][i], min(de[j][i - k], min(ae[j][i - k] + 2, ne[j][i - k] + 2))); } printf("%d\n", min(min(ne[l2][l1], ae[l2][l1]), de[l2][l1])); } return 0; }
O(N2):
addEnd[i][j]表示通过增加字符,使得str1[0 : j]变换为str2[0 : i];
delEnd[i][j]表示通过删除字符,使得str1[0 : j]变换为str2[0 : i];
noEnd[i][j]表示不做变换,使得str1[0 : j]变换为str2[0 : i]。
#include <iostream> #include <cstring> using namespace std; #define max 2001 #define INF 10000 int addEnd[max][max]; int delEnd[max][max]; int noEnd[max][max]; int MIN(int x,int y) { if(x>y) return y; else return x; } void initArray(int addEnd[][max], int delEnd[][max], int noEnd[][max], int len1, int len2) { for(int i = 0; i <= len1; i++) { delEnd[0][i] = 2; addEnd[0][i] = noEnd[0][i] = INF; } for(int i = 0;i <= len2; i++) { addEnd[i][0] = i + 2; delEnd[i][0] = noEnd[i][0] = INF; } noEnd[0][0] = 0; } void refreshArray(int addEnd[][max],int delEnd[][max],int noEnd[][max],const char* str1,int len1,const char* str2,int len2) { for(int i = 1;i <= len2; i++) { for(int j = 1;j <= len1; j++) { noEnd[i][j] = (str1[j-1]==str2[i-1]) ? MIN(addEnd[i-1][j-1],MIN(delEnd[i-1][j-1],noEnd[i-1][j-1])) : INF; delEnd[i][j] = addEnd[i][j] = INF; addEnd[i][j] = MIN(addEnd[i][j], MIN(addEnd[i-1][j]+1, MIN(delEnd[i-1][j]+1+2, noEnd[i-1][j]+1+2))); delEnd[i][j] = MIN(delEnd[i][j],MIN(addEnd[i][j-1]+2,MIN(delEnd[i][j-1],noEnd[i][j-1]+2))); } } } int main() { int num; while(cin >> num) { int ret[num]; int retID = 0; int retSize = num; while(num > 0) { char str1[max]; char str2[max]; cin >> str1 >> str2; int len1 = strlen(str1); int len2 = strlen(str2); //数组边界预定义 initArray(addEnd, delEnd, noEnd, len1, len2); //刷新数组 refreshArray(addEnd, delEnd, noEnd, str1, len1, str2, len2); //保存结果 ret[retID++] = MIN(addEnd[len2][len1],MIN(delEnd[len2][len1],noEnd[len2][len1])); //此处,切不可使用++retID(先自增为1,并将自增后的值赋给下标);而retID++是自增,并将自增前的值赋给小标。 回忆一下STL中map删除中 it++的用法 --num; }//end while //result display for(int i = 0; i < retSize; i++) { cout << ret[i] << endl; } }//end while return 0; }